user-icon Stefan Ludwig
15. December 2016
timer-icon 2 min

JUnit 5 Extension Lifecycle

Update 09.01.2017: The JUnit team decided to include my issue in the next milestone release (M4). With that, the TestInstancePostProcessor extension points will be executed, even if the extension is only active for a single method!

When writing or using extensions in JUnit 5 we should know exactly how and when they are invoked. Not knowing might confuse you with unexpected behavior!

Let’s start with a simple test class containing two tests and all regular lifecycle methods:

Executing this class produces the following output:

This is the same basic lifecycle as it has been since JUnit 4 and will serve as our baseline.

Now let’s implement an extension class implementing all available lifecycle extension points:

  • TestInstancePostProcessor
  • BeforeAllCallback
  • BeforeEachCallback
  • BeforeTestExecutionCallback
  • AfterTestExecutionCallback
  • AfterEachCallback
  • AfterAllCallback

This extension follows the same principle as the test methods by logging the extension point’s name when executed. When we activate this extension on our test class, we get the following output:

This is exactly the behaviour I would expect.

It gets a little bit more interesting when we use our extension on a single test method, instead of the whole class. When we do this, we get the following output:

As you can see, the static BeforeAllCallback and AfterAllCallback as well as the TestInstancePostProcessor extension points are no longer executed. Since the extension is only used on a single test method, it makes sense that the static callbacks are skipped. In my opinion, skipping the test instance post processing makes a little bit less sense. I have my theories why they skipped it. After all, it is hard to imagine a usecase for processing the test class instance differently for different test methods. But it also would not hurt to execute the post processors, since every  method gets its own instance anyway. (See update for the TestInstancePostProcessor extensions!)

As a final example, let’s clone our extension and change the output to include #1 and #2 as an identification. This will demonstrate how the order, in which extensions are declared, matches the order in which they are invoked.

If we declare the extension like this:

We get output like this:

This is no accident – as described in the official documentation (chapter 5.2.1). We use this to our advantage in WebTester’s JUnit 5 support module.

As always, you can find the code of these examples on GitHub. If you want to know more about why the test instance post processor extensions are not invoked on a method level, checkout this issue I opened on GitHub.

Comment article