Thursday, July 26, 2012

JUnit's Built-in Hamcrest Core Matcher Support


In the post Improving On assertEquals with JUnit and Hamcrest, I briefly discussed Hamcrest "core" matchers being "baked in" with modern versions of JUnit. In that post, I focused particularly on use of JUnit's assertThat(T, Matcher) static method coupled with the Hamcrest core is() matcher that is automatically included in later versions of JUnit. In this post, I look at additional Hamcrest "core" matchers that are bundled with recent versions of JUnit.
Two of the advantages of JUnit including Hamcrest "core" matchers out-of-the-box is that there is no need to specifically download Hamcrest and there is no need to include it explicitly on the unit test classpaths. Before looking at more of the handy Hamcrest "core" matchers, it is important to point out here that I am intentionally and repeatedly referring to "core" Hamcrest matchers because recent versions of JUnit only provide "core" (and not all) Hamcrest matchers automatically. Any Hamcrest matchers outside of the core matchers would still need to be downloaded separately and specified explicitly on the unit test classpath. One way to get an idea of what is Hamcrest "core" (and thus what matchers are available by default in recent versions of JUnit) is to look at that package's Javadoc-based API documentation:
From this JUnit-provided documentation for the org.hamcrest.core package, we see that the following matchers (with their descriptions) are available:
ClassJavadoc Class DescriptionCovered Here?
AllOf<T>Calculates the logical conjunction of two matchers.Yes
AnyOf<T>Calculates the logical disjunction of two matchers.Yes
DescribedAs<T>Provides a custom description to another matcher.Yes
Is<T>Decorates another Matcher, retaining the behavior but allowing tests to be slightly more expressive.Again
IsAnything<T>A matcher that always returns true.No
IsEqual<T>Is the value equal to another value, as tested by the Object.equals(java.lang.Object) invokedMethod?Yes
IsInstanceOfTests whether the value is an instance of a class.Yes
IsNot<T>Calculates the logical negation of a matcher.Yes
IsNull<T>Is the value null?Yes
IsSame<T>Is the value the same object as another value?Yes
In my previous post demonstrating the Hamcrest is() matcher used in conjunction with JUnit'sassertThat(), I used an IntegerArithmetic implementation as test fodder. I'll use that again here for demonstrating some of the other Hamcrest core matchers. For convenience, that class is reproduced below.



IntegerArithmetic.java
  1. package dustin.examples;  
  2.   
  3. /** 
  4.  * Simple class supporting integer arithmetic. 
  5.  *  
  6.  * @author Dustin 
  7.  */  
  8. public class IntegerArithmetic  
  9. {  
  10.    /** 
  11.     * Provide the product of the provided integers. 
  12.     *  
  13.     * @param firstInteger First integer to be multiplied. 
  14.     * @param secondInteger Second integer to be multiplied. 
  15.     * @param integers Integers to be multiplied together for a product. 
  16.     * @return Product of the provided integers. 
  17.     * @throws ArithmeticException Thrown in my product is too small or too large 
  18.     *     to be properly represented by a Java integer. 
  19.     */  
  20.    public int multiplyIntegers(  
  21.       final int firstInteger, final int secondInteger, final int ... integers)  
  22.    {  
  23.       int returnInt = firstInteger * secondInteger;  
  24.       for (final int integer : integers)  
  25.       {  
  26.          returnInt *= integer;  
  27.       }  
  28.       return returnInt;  
  29.    }  
  30. }  
In the Improving On assertEquals with JUnit and Hamcrest post, I relied largely on is() to compare expected results to actual results for the integer multiplication being tested. Another option would have been to use the equalTo matcher as shown in the next code listing.
Using Hamcrest equalTo()
  1. /** 
  2.  * Test of multiplyIntegers method, of class IntegerArithmetic, using core 
  3.  * Hamcrest matcher equalTo. 
  4.  */  
  5. @Test  
  6. public void testWithJUnitHamcrestEqualTo()  
  7. {  
  8.    final int[] integers = {456789101112131415};  
  9.    final int expectedResult = 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 *13 * 14 * 15;  
  10.    final int result = this.instance.multiplyIntegers(23, integers);  
  11.    assertThat(result, equalTo(expectedResult));  
  12. }  
Although not necessary, some developers like to use is and equalTo together because it feels more fluent to them. This is the very reason for is's existence: to make use of other matchers more fluent. I often use is() by itself (implying equalTo()) as discussed in Improving On assertEquals with JUnit and Hamcrest. The next example demonstrates using is() matcher in conjunction with the equalTomatcher.
Using Hamcrest equalTo() with is()
  1. /** 
  2.  * Test of multiplyIntegers method, of class IntegerArithmetic, using core 
  3.  * Hamcrest matcher equalTo with "is" Matcher.. 
  4.  */  
  5. @Test  
  6. public void testWithJUnitHamcrestEqualToAndIsMatchers()  
  7. {  
  8.    final int[] integers = {456789101112131415};  
  9.    final int expectedResult = 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 *13 * 14 * 15;  
  10.    final int result = this.instance.multiplyIntegers(23, integers);  
  11.    assertThat(result, is(equalTo(expectedResult)));  
  12. }  
The equalTo Hamcrest matcher performs a comparison similar to calling Object.equals(Object). Indeed, its comparison functionality relies on use of the underlying object's equals(Object)implementation. This means that the last two examples will pass because the numbers being compared are logically equivalent. When one wants to ensure an even greater identity equality (actually the same objects and not just the same logical content), one can use the Hamcrest sameInstance matcher as shown in the next code listing. The not matcher is also applied because the assertion will be true and the test will pass only with the "not" in place because the expected and actual results happen to NOT be the same instances!
Using Hamcrest sameInstance() with not()
  1. /** 
  2.  * Test of multiplyIntegers method, of class IntegerArithmetic, using core 
  3.  * Hamcrest matchers not and sameInstance. 
  4.  */  
  5. @Test  
  6. public void testWithJUnitHamcrestNotSameInstance()  
  7. {  
  8.    final int[] integers = {456789101112131415};  
  9.    final int expectedResult = 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 *13 * 14 * 15;  
  10.    final int result = this.instance.multiplyIntegers(23, integers);  
  11.    assertThat(result, not(sameInstance(expectedResult)));  
  12. }  
It is sometimes desirable to control the text that is output from an assertion of a failed unit test. JUnit includes the core Hamcrest matcher asDescribed() to support this. A code example of this is shown in the next listing and the output of that failed test (and corresponding assertion) is shown in the screen snapshot of the NetBeans IDE that follows the code listing.
Using Hamcrest asDescribed() with sameInstance()
  1. /** 
  2.  * Test of multiplyIntegers method, of class IntegerArithmetic, using core 
  3.  * Hamcrest matchers sameInstance and asDescribed. This one will assert a 
  4.  * failure so that the asDescribed can be demonstrated (don't do this with 
  5.  * your unit tests as home)! 
  6.  */  
  7. @Test  
  8. public void testWithJUnitHamcrestSameInstanceDescribedAs()  
  9. {  
  10.    final int[] integers = {456789101112131415};  
  11.    final int expectedResult = 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 *13 * 14 * 15;  
  12.    final int result = this.instance.multiplyIntegers(23, integers);  
  13.    assertThat(result,  
  14.               describedAs(  
  15.                  "Not same object (different identity reference)",  
  16.                  sameInstance(expectedResult)));  
  17. }  
Use of describedAs() allowed the reporting of a more meaningful message when the associated unit test assertion failed.
I am going to now use another contrived class to help illustrate additional core Hamcrest matchers available with recent versions of JUnit. This that "needs testing" is shown next.
SetFactory.java
  1. package dustin.examples;  
  2.   
  3. import java.lang.reflect.InvocationTargetException;  
  4. import java.util.*;  
  5. import java.util.logging.Level;  
  6. import java.util.logging.Logger;  
  7.   
  8. /** 
  9.  * A Factory that provides an implementation of a Set interface based on 
  10.  * supplied SetType that indicates desired type of Set implementation. 
  11.  *  
  12.  * @author Dustin 
  13.  */  
  14. public class SetFactory<T extends Object>  
  15. {  
  16.    public enum SetType  
  17.    {  
  18.       ENUM(EnumSet.class),  
  19.       HASH(HashSet.class),  
  20.       SORTED(SortedSet.class), // SortedSet is an interface, not implementation  
  21.       TREE(TreeSet.class),  
  22.       RANDOM(Set.class);       // Set is an interface, not a concrete collection  
  23.   
  24.       private Class setTypeImpl = null;  
  25.   
  26.       SetType(final Class newSetType)  
  27.       {  
  28.          this.setTypeImpl = newSetType;  
  29.       }  
  30.   
  31.       public Class getSetImplType()  
  32.       {  
  33.          return this.setTypeImpl;  
  34.       }  
  35.    }  
  36.   
  37.    private SetFactory() {}  
  38.   
  39.    public static SetFactory newInstance()  
  40.    {  
  41.       return new SetFactory();  
  42.    }  
  43.   
  44.    /** 
  45.     * Creates a Set using implementation corresponding to the provided Set Type 
  46.     * that has a generic parameterized type of that specified. 
  47.     *  
  48.     * @param setType Type of Set implementation to be used. 
  49.     * @param parameterizedType Generic parameterized type for the new set. 
  50.     * @return Newly constructed Set of provided implementation type and using 
  51.     *    the specified generic parameterized type; null if either of the provided 
  52.     *    parameters is null. 
  53.     * @throws ClassCastException Thrown if the provided SetType is SetType.ENUM, 
  54.     *    but the provided parameterizedType is not an Enum. 
  55.     */  
  56.    public Set<T> createSet(  
  57.       final SetType setType, final Class<T> parameterizedType)  
  58.    {  
  59.       if (setType == null || parameterizedType == null)  
  60.       {  
  61.          return null;  
  62.       }  
  63.   
  64.       Set<T> newSet = null;  
  65.       try  
  66.       {  
  67.          switch (setType)  
  68.          {  
  69.             case ENUM:  
  70.                if (parameterizedType.isEnum())  
  71.                {  
  72.                   newSet = EnumSet.noneOf((Class<Enum>)parameterizedType);  
  73.                }  
  74.                else  
  75.                {  
  76.                   throw new ClassCastException(  
  77.                        "Provided SetType of ENUM being supplied with "  
  78.                      + "parameterized type that is not an enum ["  
  79.                      + parameterizedType.getName() + "].");  
  80.                }  
  81.                break;  
  82.             case RANDOM:  
  83.                newSet = LinkedHashSet.class.newInstance();  
  84.                break;  
  85.             case SORTED:  
  86.                newSet = TreeSet.class.newInstance();  
  87.                break;  
  88.             default:  
  89.                newSet = (Set<T>) setType.getSetImplType().getConstructor().newInstance();  
  90.                break;  
  91.          }  
  92.       }  
  93.       catch (  InstantiationException  
  94.              | IllegalAccessException  
  95.              | IllegalArgumentException  
  96.              | InvocationTargetException  
  97.              | NoSuchMethodException ex)  
  98.       {  
  99.          Logger.getLogger(SetFactory.class.getName()).log(Level.SEVERE, null, ex);  
  100.       }  
  101.       return newSet;  
  102.    }  
  103. }  
The contrived class whose code was just shown provides opportunities to use additional Hamcrest "core" matchers. As described above, it's possible to use all of these matches with the is matcher to improve fluency of the statement. Two useful "core" matchers are nullValue() andnotNullValue(), both of which are demonstrated in the next JUnit-based code listing (and is is used in conjunction in one case).
Using Hamcrest nullValue() and notNullValue()
  1. /** 
  2.  * Test of createSet method, of class SetFactory, with null SetType passed. 
  3.  */  
  4. @Test  
  5. public void testCreateSetNullSetType()  
  6. {  
  7.    final SetFactory factory = SetFactory.newInstance();  
  8.    final Set<String> strings = factory.createSet(null, String.class);  
  9.    assertThat(strings, nullValue());  
  10. }  
  11.   
  12. /** 
  13.  * Test of createSet method, of class SetFactory, with null parameterized type 
  14.  * passed. 
  15.  */  
  16. @Test  
  17. public void testCreateSetNullParameterizedType()  
  18. {  
  19.    final SetFactory factory = SetFactory.newInstance();  
  20.    final Set<String> strings = factory.createSet(SetType.TREE, null);  
  21.    assertThat(strings, is(nullValue()));  
  22. }  
  23.   
  24. @Test  
  25. public void testCreateTreeSetOfStringsNotNullIfValidParams()  
  26. {  
  27.    final SetFactory factory = SetFactory.newInstance();  
  28.    final Set<String> strings = factory.createSet(SetType.TREE, String.class);  
  29.    assertThat(strings, notNullValue());  
  30. }  
The Hamcrest matcher instanceOf is also useful and is demonstrated in the next code listing (one example using instanceOf by itself and one example using it in conjunction with is).
Using Hamcrest instanceOf()
  1. @Test  
  2. public void testCreateTreeSetOfStringsIsTreeSet()  
  3. {  
  4.    final SetFactory factory = SetFactory.newInstance();  
  5.    final Set<String> strings = factory.createSet(SetType.TREE, String.class);  
  6.    assertThat(strings, is(instanceOf(TreeSet.class)));  
  7. }  
  8.   
  9. @Test  
  10. public void testCreateEnumSet()  
  11. {  
  12.    final SetFactory factory = SetFactory.newInstance();  
  13.    final Set<RoundingMode> roundingModes = factory.createSet(SetType.ENUM, RoundingMode.class);  
  14.    roundingModes.add(RoundingMode.UP);  
  15.    assertThat(roundingModes, instanceOf(EnumSet.class));  
  16. }  
Many of the Hamcrest core matchers covered so far increase fluency and readability, but I like the next two for even more reasons. The Hamcrest hasItem() matcher checks for the existence of the prescribed item in the collection and the even more useful Hamcrest hasItems() matcher checks for the existence of multiple prescribed items in the collection. It is easier to see this in code and the following code demonstrates these in action.
Using Hamcrest hasItem() and hasItems()
  1. @Test  
  2. public void testCreateTreeSetOfStringsHasOneOfAddedStrings()  
  3. {  
  4.    final SetFactory factory = SetFactory.newInstance();  
  5.    final Set<String> strings = factory.createSet(SetType.TREE, String.class);  
  6.    strings.add("Tucson");  
  7.    strings.add("Arizona");  
  8.    assertThat(strings, hasItem("Tucson"));  
  9. }  
  10.   
  11. @Test  
  12. public void testCreateTreeSetOfStringsHasAllOfAddedStrings()  
  13. {  
  14.    final SetFactory factory = SetFactory.newInstance();  
  15.    final Set<String> strings = factory.createSet(SetType.TREE, String.class);  
  16.    strings.add("Tucson");  
  17.    strings.add("Arizona");  
  18.    assertThat(strings, hasItems("Tucson""Arizona"));  
  19. }  
It is sometimes desirable to test the result of a certain tested method to ensure that it meets a wide variety of expectations. This is where the Hamcrest allOf matcher comes in handy. This matcher ensures that all conditions (expressed themselves as matchers) are true. This is illustrated in the following code listing, which tests with a single assert that a generated Set is not null, has two specific Strings in it, and is an instance of TreeSet.
Using Hamcrest allOf()
  1. @Test  
  2. public void testCreateSetAllKindsOfGoodness()  
  3. {  
  4.    final SetFactory factory = SetFactory.newInstance();  
  5.    final Set<String> strings = factory.createSet(SetType.TREE, String.class);  
  6.    strings.add("Tucson");  
  7.    strings.add("Arizona");  
  8.    assertThat(  
  9.       strings,  
  10.       allOf(  
  11.          notNullValue(), hasItems("Tucson""Arizona"), instanceOf(TreeSet.class)));  
  12. }  
To demonstrate the Hamcrest core "anyOf" matcher provided out-of-the-box with newer versions of JUnit, I am going to use yet another ridiculously contrived Java class that is in need of a unit test.
Today.java
  1. package dustin.examples;  
  2.   
  3. import java.util.Calendar;  
  4. import java.util.Locale;  
  5.   
  6. /** 
  7.  * Provide what day of the week today is. 
  8.  *  
  9.  * @author Dustin 
  10.  */  
  11. public class Today  
  12. {  
  13.    /** 
  14.     * Provide the day of the week of today's date. 
  15.     *  
  16.     * @return Integer representing today's day of the week, corresponding to 
  17.     *    static fields defined in Calendar class. 
  18.     */  
  19.    public int getTodayDayOfWeek()  
  20.    {  
  21.       return Calendar.getInstance(Locale.US).get(Calendar.DAY_OF_WEEK);  
  22.    }  
  23. }  
Now I need to test that the sole method in the class above returns a valid integer representing a day of the week correctly. I'd like my test(s) to ensure that a valid integer representing a day Sunday through Saturday is returned, but the method being tested is such that it may not be the same day of the week returned on any given test run. The code listing below indicates how this can be tested with the JUnit-included Hamcrest "anyOf" matcher.
Using Hamcrest anyOf()
  1. /** 
  2.  * Test of getTodayDayOfWeek method, of class Today. 
  3.  */  
  4. @Test  
  5. public void testGetTodayDayOfWeek()  
  6. {  
  7.    final Today instance = new Today();  
  8.    final int todayDayOfWeek = instance.getTodayDayOfWeek();  
  9.    assertThat(todayDayOfWeek,  
  10.               describedAs(  
  11.                  "Day of week not in range.",  
  12.                  anyOf(is(Calendar.SUNDAY),  
  13.                        is(Calendar.MONDAY),  
  14.                        is(Calendar.TUESDAY),  
  15.                        is(Calendar.WEDNESDAY),  
  16.                        is(Calendar.THURSDAY),  
  17.                        is(Calendar.FRIDAY),  
  18.                        is(Calendar.SATURDAY))));  
  19. }  
While Hamcrest's allOf requires all conditions to match for the assertion to be avoided, the existence of any one condition is sufficient to ensure that anyOf doesn't lead to an assertion of a failure.
My favorite way of determining which core Hamcrest matchers are available with JUnit is to use import completion in my Java IDE. When I statically import the org.hamcrest.CoreMatchers.* package contents, all of the available matchers are displayed. I can look in the IDE to see what the * represents to see what matchers are available to me.
It is nice to have Hamcrest "core" matchers included with JUnit and this post has attempted to demonstrate the majority of these. Hamcrest offers many useful matchers outside of the "core" that are useful as well. More details on these are available in the Hamcrest Tutorial.

NetBeans 7.2 Introduces TestNG


One of the advantages of code generation is the ability to see how a specific language feature or framework is used. As I discussed in the post NetBeans 7.2 beta: Faster and More HelpfulNetBeans 7.2 beta provides TestNG integration. I did not elaborate further in that post other than a single reference to that feature because I wanted to devote this post to the subject. I use this post to demonstrate how NetBeans 7.2 can be used to help a developer new to TestNG start using this alternative (to JUnit) test framework.
NetBeans 7.2's New File wizard makes it easier to create an empty TestNG test case. This is demonstrated in the following screen snapshots that are kicked off by using New File | Unit Tests (note that "New File" is available under the "File" drop-down menu or by right-clicking in the Projects window).
Running the TestNG test case creation as shown above leads to the following generated test code.
TestNGDemo.java (Generated by NetBeans 7.2)
  1. package dustin.examples;  
  2.   
  3. import org.testng.annotations.AfterMethod;  
  4. import org.testng.annotations.AfterClass;  
  5. import org.testng.annotations.BeforeMethod;  
  6. import org.testng.annotations.BeforeClass;  
  7. import org.testng.annotations.Test;  
  8. import org.testng.Assert;  
  9.   
  10. /** 
  11.  * 
  12.  * @author Dustin 
  13.  */  
  14. public class TestNGDemo  
  15. {     
  16.    public TestNGDemo()  
  17.    {  
  18.    }  
  19.      
  20.    @BeforeClass  
  21.    public void setUpClass()  
  22.    {  
  23.    }  
  24.      
  25.    @AfterClass  
  26.    public void tearDownClass()  
  27.    {  
  28.    }  
  29.      
  30.    @BeforeMethod  
  31.    public void setUp()  
  32.    {  
  33.    }  
  34.      
  35.    @AfterMethod  
  36.    public void tearDown()  
  37.    {  
  38.    }  
  39.    // TODO add test methods here.  
  40.    // The methods must be annotated with annotation @Test. For example:  
  41.    //  
  42.    // @Test  
  43.    // public void hello() {}  
  44. }  
The test generated by NetBeans 7.2 includes comments indicate how test methods are added and annotated (similar to modern versions of JUnit). The generated code also shows some annotations for overall test case set up and tear down and for per-test set up and tear down (annotations are similar to JUnit's). NetBeans identifies import statements that are not yet used at this point (import org.testng.annotations.Test; and import org.testng.Assert;), but are likely to be used and so have been included in the generated code.
I can add a test method easily to this generated test case. The following code snippet is a test method using TestNG.
testIntegerArithmeticMultiplyIntegers()
  1. @Test  
  2. public void testIntegerArithmeticMultiplyIntegers()  
  3. {  
  4.    final IntegerArithmetic instance = new IntegerArithmetic();  
  5.    final int[] integers = {456};  
  6.    final int expectedProduct = 2 * 3 * 4 * 5 * 6;  
  7.    final int product = instance.multiplyIntegers(23, integers);  
  8.    assertEquals(product, expectedProduct);  
  9. }  
This, of course, looks very similar to the JUnit equivalent I used against the same IntegerArithmeticclass that I used for testing illustrations in the posts Improving On assertEquals with JUnit and Hamcrestand JUnit's Built-in Hamcrest Core Matcher Support. The following screen snapshot shows the output in NetBeans 7.2 beta from right-clicking on the test case class and selecting "Run File" (Shift+F6).
The text output of the TestNG run provided in the NetBeans 7.2 beta is reproduced next.
[TestNG] Running:
  Command line suite

[VerboseTestNG] RUNNING: Suite: "Command line test" containing "1" Tests (config: null)
[VerboseTestNG] INVOKING CONFIGURATION: "Command line test" - @BeforeClass dustin.examples.TestNGDemo.setUpClass()
[VerboseTestNG] PASSED CONFIGURATION: "Command line test" - @BeforeClass dustin.examples.TestNGDemo.setUpClass() finished in 33 ms
[VerboseTestNG] INVOKING CONFIGURATION: "Command line test" - @BeforeMethod dustin.examples.TestNGDemo.setUp()
[VerboseTestNG] PASSED CONFIGURATION: "Command line test" - @BeforeMethod dustin.examples.TestNGDemo.setUp() finished in 2 ms
[VerboseTestNG] INVOKING: "Command line test" - dustin.examples.TestNGDemo.testIntegerArithmeticMultiplyIntegers()
[VerboseTestNG] PASSED: "Command line test" - dustin.examples.TestNGDemo.testIntegerArithmeticMultiplyIntegers() finished in 12 ms
[VerboseTestNG] INVOKING CONFIGURATION: "Command line test" - @AfterMethod dustin.examples.TestNGDemo.tearDown()
[VerboseTestNG] PASSED CONFIGURATION: "Command line test" - @AfterMethod dustin.examples.TestNGDemo.tearDown() finished in 1 ms
[VerboseTestNG] INVOKING CONFIGURATION: "Command line test" - @AfterClass dustin.examples.TestNGDemo.tearDownClass()
[VerboseTestNG] PASSED CONFIGURATION: "Command line test" - @AfterClass dustin.examples.TestNGDemo.tearDownClass() finished in 1 ms
[VerboseTestNG] 
[VerboseTestNG] ===============================================
[VerboseTestNG]     Command line test
[VerboseTestNG]     Tests run: 1, Failures: 0, Skips: 0
[VerboseTestNG] ===============================================

===============================================
Command line suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================

Deleting directory C:\Users\Dustin\AppData\Local\Temp\dustin.examples.TestNGDemo
test:
BUILD SUCCESSFUL (total time: 2 seconds)
The above example shows how easy it is to start using TestNG, especially if one is moving to TestNG from JUnit and is using NetBeans 7.2 beta. Of course, there is much more to TestNG than this, but learning a new framework is typically most difficult at the very beginning and NetBeans 7.2 gets one off to a fast start.