December 30, 2016

JUnit 5! What's new?

JUnit 5 is finally out. I will take this opportunity, to introduce some of its new features. I will point out only the features that I have found most interesting.

Annotations

The JUnit Team has changed a lot of the annotation names so that it is clearer how and when they should be used. The underlying behaviour is still the same. Methods which are annotated with either @BeforeAll or @AfterAll must be static because each test creates a new instance, and, therefore, it is unclear on which instance they have to be invoked. [1]


  • @TestFactory – denotes a method that is a test factory for dynamic tests
  • @DisplayName – defines custom display name for a test class or a test method
  • @Nested – denotes that the annotated class is a nested, non-static test class
  • @Tag – declares tags for filtering tests
  • @ExtendWith – it is used to register custom extensions
  • @BeforeEach – denotes that the annotated method will be executed before each test method (previously @Before)
  • @AfterEach – denotes that the annotated method will be executed after each test method (previously @After)
  • @BeforeAll – denotes that the annotated method will be executed before all test methods in the current class (previously @BeforeClass)
  • @AfterAll – denotes that the annotated method will be executed after all test methods in the current class  (previously @AfterClass)
  • @Disable – it is used to disable a test class or method (previously @Ignore)

Test Method Visibility

Tests need not to be public anymore. It is now possible that to use package visibility only.

Tags - Custom Annotations

It is now possible to create your own annotations. For example, in the past if you wanted to tag your methods or test classes you had to use the @Tag("someTagName"). Therefore, the JUnit Team has now made it possible to create a custom annotation, which will inherit from its meta-annotation. This enables users to filter the tests that should run based on their tag name. In the plugin section of the maven-surefire-plugin you can define the properties of whichever tag you want to include or exclude.

For including, you can use the properties groups or includeTags, and for excluding, you can use excludedGroups or excludeTags as you can see in the following code snippet.

 <plugin>  
     <artifactId>maven-surefire-plugin</artifactId>  
     <version>2.19</version>  
      <configuration>  
         <properties>  
           <includeTags>fastRunning</includeTags>  
           <excludeTags>slowRunning, needRework</excludeTags>  
         </properties>  
      </configuration>            
 </plugin>  

To create custom annotations you can do as described in the official user guide of JUnit [1]. After declaring it you can use the @FastRunning annotation everywhere where you would have used @Tag("fastRunning").

 import java.lang.annotation.ElementType;  
 import java.lang.annotation.Retention;  
 import java.lang.annotation.RetentionPolicy;  
 import java.lang.annotation.Target;  
 import org.junit.jupiter.api.Tag;  
 @Target({ ElementType.TYPE, ElementType.METHOD })  
 @Retention(RetentionPolicy.RUNTIME)  
 @Tag("fastRunning")  
 public @interface FastRunning {  
 }  

Exceptions

If a method was going to throw an exception, in the past you needed to declare the thrown exception in the Test annotation, like this @Test(expected = NullPointerException.class). JUnit 5 has introduced a new method called assertThrows().

 @Test  
 void shouldThrowException() {  
   Throwable exception = expectThrows(UnsupportedOperationException.class, () -> doSomething());  
   assertEquals(exception.getMessage(), "Some Exception Message");  
 }  

This method makes it possible to work with the exception object. It gives users more control over the exception than just throwing it. The Throwable object holds all information about the exception, so it is easy to test the exception in a more detailed way than before.

Assume

Assume is an interesting feature which ensures that your tests won't fail in certain situations. For example, if you have developers working on different operating systems, you can put in a condition at the beginning of the test such that the test will only fully run on an operating system other than Windows. With assumeTrue if the condition fails, everything that is written beneath it will not be executed. You can see an example in the following code snippet.

Conclusion

Some of the new features of JUnit 5 are really interesting. From my point of view, being able to examine thrown exceptions and not just the thrown class in more detail is a great improvement. The assume assumptions are also great to have because they will help your tests to run more stably in certain situations.

No comments:

Post a Comment