Basic pom configuration

The Surefire plugin detects test classes, loads a test engine and delegates test execution to that engine. Surefire is available by default, JUnit or TestNG must be added as dependency. For JUnit it is almost straightforward:

      <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <scope>test</scope>
      </dependency>

As you see verion number is omitted. JUnit advises to load their BOM (Bill of Materials) via <dependencyManagement>. By doing so jupiter will inherit the right version number, just like other JUnit stuff you might add as dependency or plugin.

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.junit</groupId>
        <artifactId>junit-bom</artifactId>
        <version>5.13.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

JUnit

JUnit is good for unit testing but you can do integration testing with it as well, I don’t know everything yet but the annotations @ExtendWith and @RegisterExtension give a clue. You can create a special class that generates a context for a testclass, for example in the form of a webserver or a database, and at the same time manages the lifecycle of this context.

Test classes must be put in src/test/java, using a copy of the directory structure of the src/main/java. Test classes must have a name starting or ending with Test, Maven will recognize this. When working with JUnit you will annotate test classes as well with @Test.

Test classes need the same package declarations as the non-test files, and the right imports from org.junit.jupiter.

JUnit annotations

JUnit has a set of annotations which I have categorized and described below. Together this gives an overview

Annotations indicating testclass or -method

   
GENERAL  
@Test Marks a test method
@ParameterizedTest Marks a test that runs multiple times. Requires a source annotation. There are many types of source annotations.
@ParameterizedClass Does the same for a whole class. The @Test methods in the class must all require the type of arguments that the source annotation provides.
@RepeatedTest Does the same test multiple times. Besides n you can set parameters like ‘failureThreshold.’
@TestFactory Marks methods that generate a stream, or some object that can be converted to a stream, of type DynamicTest or DynamicContainer. A DynamicTest object is composed of a display name (String) and a test of type <Executable>, which is a functional interface representing a test. It typically has an ‘assert’ in its body. It throws a Throwable which makes it different from Runnable. DynamicContainer is composed of a display name and an Iterable or Stream of <DynamicNode> objects. DynamicNode is the abstract parent class of both DynamicNode and DynamicTest. It means you can do nesting when you use DynamicContainer instead of DynamicTest.
@TestTemplate Marks a test that will be executed multiple times using a stream of <TestTemplateInvocationContext> instances. The test must be able to withstand multiple ‘contexts’. The stream of TestTemplateInvocationContext objects is contained in a <TestTemplateInvocationContextProvider>, which you must create and then feed to the method annotated with @TestTemplate using ‘@ExtendWith.’ The latter is one of the ways to providing contexts to methods.
@ClassTemplate Same as @TestTemplate but here a class is created with methods in it that will all be tested with a context provided by ClassTemplateInvocationContextProvider, a class that has a ‘provideClassTemplateInvocationContexts’ method that returns a stream or iterable of ClassTemplateInvocationContext objects.
EXECUTION ORDER  
@TestClassOrder Marking class with this annotation allows you to define in which order nested classes will be executed. It is also possible to define the order of execution of first-order classes, this requires configuration in ‘src/test/resources/junit-platform.properties’ plus adding the @Order annotation to classes you want to order (or not, if you choose to order alphabetically for example).
@TestMethodOrder Same as previous, but plays out one level lower. Apply this to the class (with OrderAnnotation.class as argument) and annotate the test methods in the class with @Order(Integer ordernumber).
KEEPING STATE  
@TestInstance By default JUnit creates a new instance for every tested method in a class, to prevent that altered state by one method affects the outcome of a test of another method. If you want to have all methods be tested with a single class instance, annotate the class with @TestInstance(Lifecycle.PER_CLASS). A byeffect is that with one class instance you can use the @AfterAll and @BeforeAll annotations on non-static methods, or at least in a meaningful way.
READABLE OUTPU  
@DisplayName Sets display name of test that will be displayed in test reports and by test runners and IDEs. Special characters and emojis allowed. You can combine it with @ParameterizedTest, @ValueSource and placeholder ({0}) to get readable sentences in your output.
@DisplayNameGeneration Applied to classes, extra options to get better readable output. For example, can convert class names with hyphens to sentences without hypens.
BEFORE/AFTER  
@BeforeEach Denotes that the annotated method should be executed before each @Test, @RepeatedTest, @ParameterizedTest, or @TestFactory method in the current class.
@AfterEach Denotes that the annotated method should be executed after each @Test, @RepeatedTest, @ParameterizedTest, or @TestFactory method in the current class.
@BeforeAll Denotes that the annotated method should be executed before all @Test, @RepeatedTest, @ParameterizedTest, and @TestFactory methods in the current class. Methods must be static or class must be annotated with @TestInstance.
@AfterAll Same as previous, only to be executed after all methods.
@BeforeParameterizedClassInvocation Denotes that the annotated method should be executed once before each invocation of a parameterized class.
@AfterParameterizedClassInvocation As previous but ‘after’.
NESTED CLASSES  
@Nested Denotes that the annotated class is a non-static nested test class. Nesting is more relevant in testing than in regular Java code, provides opportunities for structured code and structured output.
FILTERING TESTS  
@Tag Used to declare tags for filtering tests, either at the class or method level
@Disabled Disables a test class or test method
CLOSING RESOURCES  
@AutoClose For fields. The built-in AutoCloseExtension automatically closes resources associated with fields. Field type must have a close() method, if not you can give an argument with the name of another method that must be executed to close the resource.
TIMEOUT  
@Timeout Tells the amount of time a test has to succeed, otherwise makes it a fail.
CONTEXT  
@TempDir Injects a Path/File instance in field or method parameter if it requires so and cleans it up after execution. If your code does something with file creation, writing, reading, this helps cause there is a Path in which you can create it.
@ExtendWith Basically about providing classes, methods, parameters, fields with a class/object that acts as a context. Enables integration testing. Good for simple, stateless contexts that can be used throughout the test suite.
@RegisterExtension Similar, but used within test class. Add it to a field that creates an object, and this object will become the context. More verbose but easier to configure because you can provide runtime arguments for the specific situation. @ExtendWith needs the class name that forms the context as an argument, so that class object is defined elsewhere without custom arguments. Better reusability but less flexibility.

<
Previous Post
Maven shade plugin
>
Next Post
Custom JUnit 5 reporting