- Parts of a Test
- Strings
- Objects
- Arrays
- Swing / AWT
- Generate Combinations of Parameter Values
- Approving The Result
- Reporters
- Supported Diff Tools
All tests (unit and otherwise) contain 2 parts:
- Do
- Verify
ApprovalTests is a way to handle the second part: Verification. All calls will look about the same:
Approvals.verify(objectToBeVerified);
Letʼs say you wanted to test if a string was being built correctly:
@Test
public void testBuildString()
{
/* Do */
// create a string with "Approval" and append "Tests" to it
String s = "Approval";
s += " Tests";
/* Verify */
// Verify the resulting string
Approvals.verify(s);
}
Will Produce the following File:
GettingStartedTest.testBuildString.approved.txt
Containing
Approval Tests
This is the 'actual result'.
The 'expected' result is in the file SampleTest.testBuildString.received.txt
(This is described in detail below.)
When you see the results you want (“ApprovalTests”) as the result,
simply Approve The Result.
Let's say that you wanted to test that a customized StringBuilder was creating text correctly:
@Test
public void testObject()
{
/* Do */
// create an 100 x 200 rectangle with the top corner at (5, 10)
Rectangle objectUnderTest = new Rectangle(5, 10, 100, 200);
/* Verify */
// Verify the rectangle is properly defined
Approvals.verify(objectUnderTest.toString());
}
Will Produce the following File:
GettingStartedTest.testObject.approved.txt
Containing
java.awt.Rectangle[x=5,y=10,width=100,height=200]
If the object does not have a toString() method defined, and you do not want to (or can not) create a custom one, you can use JSON to verify the contents of an object:
JsonApprovals.verifyAsJson(objectUnderTest);
Will Produce the following File:
GettingStartedTest.testObjectWithJson.approved.json
Containing
{
"x": 5,
"y": 10,
"width": 100,
"height": 200
}
If you see “ApprovalTests” as the result, simply Approve The Result. Itʼs important to note that you will need to create a useful instance of the toString() Method for objects you want to use.
Letʼs say you wanted to test an array of Strings:
@Test
public void testArray()
{
/* Do */
// create a String Array and set values in the indexes
String[] s = new String[2];
s[0] = "Approval";
s[1] = "Tests";
/* Verify */
// Verify the array
Approvals.verifyAll("Text", s);
}
Will Produce the following File:
Text[0] = Approval
Text[1] = Tests
Note the use of the label, "Text". This is used to make the generated output easier to read:
Again, simply Approve The Result
Letʼs say you wanted to test that youʼve created a JPanel correctly. (This works for anything that extends java.awt.Component : awt, swing, JFrame, Label, etc...)
/* Do */
// create a TV Guide and select a show for 3pm
TvGuide tv = new TvGuide();
tv.selectTime("3pm");
/* Verify */
// Verify the TvGuide
AwtApprovals.verify(tv);
Will Produce the following File:
First, I want to note that even though there is a UI and a select box for times, Iʼm not “poking” it to select the time. Just because we are looking at the UI at the end, doesnʼt mean I need to manipulate it directly. We are programmers, and are not limited by the constraints of the UI. I simply expose a selectTime(String value) function.
Second, this will produce a .png file containing a screen shot of the JPanel as a result. Simply Approve The Result when itʼs ready.
Third, because these will render differently on different operating systems. These test automatically include a Machine Specific setting NamerFactory.asOsSpecificTest() which adds the os type (e.g: Mac_OS_X) to the file name
To simplify getting more comprehensive sets of test cases, or expanding code coverage, ApprovalTests can generate combinations of possible parameters for a given function.
To do this, create an array of possible values for each parameter passed to a function (up to nine parameters). Call the CombinationApprovals.verifyAllCombinations() method passing the method to be called as a lambda. An example follows:
Integer[] lengths = new Integer[]{4, 5, 10};
String[] words = new String[]{"Bookkeeper", "applesauce"};
CombinationApprovals.verifyAllCombinations((i, s) -> s.substring(0, i), lengths, words);
Will Produce the following File:
[4, Bookkeeper] => Book
[4, applesauce] => appl
[5, Bookkeeper] => Bookk
[5, applesauce] => apple
[10, Bookkeeper] => Bookkeeper
[10, applesauce] => applesauce
Note on using primitives:
We need to use Integer
rather than int
so that Java generics will work properly.
Here we are writing a single test that tries all 6 ( 3 ints * 2 String) combinations of inputs and the results those will produce.
This will generate potentially hundreds or thousands of possible combinations of values. As before, the output will be displayed and, if the results are satisfactory, Approve The Result.
When you run a test using ApprovalTests, it will generate a file named
YourTestClass.yourTestMethod.received.txt
(or .png, .html, etc.) and place it in the same
directory as your test.
For the test to pass, this file must match:
YourTestClass.youTestMethod.approved.txt
There are many ways to do this:
- Rename the .received file
- Run the "move" command that is displayed (also added to your clipboard) in the command line
- Use "use whole file" on a diff reporter
It doesnʼt matter how you do it.
Note: If the files match, then the received file will be deleted.
Note: You must include the .approved.
files in your source control.
If an approval fails, then a reporter will be called that will report the “.received” and “.approved” files. There are many reporters, and you can create your own.
The simplest way to have your reporter called is to use the Annotation @UseReporter(Reporter.class) You can annotate at either the method or class level.
Here are some common Reporters and uses
Reporter | Description |
---|---|
ClipboardReporter | Puts the "move" command to accept the "received" file as the "approved" file |
DiffReporter | Launches an instance of the specified reporter |
FileLauncherReporter | Opens the .received file in the specified editor |
ImageReporter | Launches an instance of the specified image diff tool |
ImageWebReporter | Opens the files in a Web browser |
JunitReporter | Text only, displays the contents of the files as an AssertEquals failure |
NotePadLauncher | Opens the .received file in Notepad++ (MS Windows only) |
QuietReporter | Outputs the "move" command to the console (great for build systems) |
TextWebReporter | Opens the text files in a Web browser |
If your diff tool of choice is not supported, or is in a non-standard install folder, you can always use a Custom Reporter