What use is @TestInstance annotation in JUnit 5?
I think the docs provide a useful summary:
If you would prefer that JUnit Jupiter execute all test methods on the same test instance, simply annotate your test class with @TestInstance(Lifecycle.PER_CLASS). When using this mode, a new test instance will be created once per test class. Thus, if your test methods rely on state stored in instance variables, you may need to reset that state in @BeforeEach or @AfterEach methods.
The "per-class" mode has some additional benefits over the default "per-method" mode. Specifically, with the "per-class" mode it becomes possible to declare @BeforeAll and @AfterAll on non-static methods as well as on interface default methods. The "per-class" mode therefore also makes it possible to use @BeforeAll and @AfterAll methods in @Nested test classes.
But you've probably read that already and you are correct in thinking that making a field static will have the same effect as declaring the field as an instance variable and using @TestInstance(Lifecycle.PER_CLASS)
.
So, perhaps the answer to the question "how it could be useful in JUnit 5" is that using a @TestInstance
...
- Is explicit about your intentions. It could be assumed that use of the static keyword was accidental whereas use of
@TestInstance
is less likely to be accidental or a result of thoughless copy-n-paste. - Delegates the responsibility for managing scope and lifecycle and clean up to the framework rather than having to remember to manage that yourself.
This annotation was introduced to reduce the number of objects created when running your unit tests.
Adding @TestInstance(TestInstance.Lifecycle.PER_CLASS)
to your test class will avoid that a new instance of your class is created for every test in the class.
This is particulary usefull when you have a lot of tests in the same test class and the instantiation of this class is expensive.
This annotation should be used with caution. All unit tests should be isolated and independent of eachother. If one of the tests changes the state od the test class then you should not use this feature.
Making your fields static to achieve the same effect is not a good idea. It will indeed reduce the number of objects created but they cannot be cleaned up when all tests in the test class are executed. This can cause problems when you have a giant test suite.
@TestInstance
is used to configure the lifecycle of test instances for the annotated test class or test interface:
-
PER_CLASS
: A new test instance will be created once per test class. -
PER_METHOD
: A new test instance will be created for each test method, test factory method, or test template method. This mode is analogous to the behavior found in JUnit versions 1 through 4.
If @TestInstance
is not explicitly declared on a test class or on a test interface implemented by a test class, the lifecycle mode will implicitly default to PER_METHOD
.
Setting the test instance lifecycle mode to PER_CLASS
enables the following features:
- Shared test instance state between test methods in a given test class as well as between non-static
@BeforeAll
and@AfterAll
methods in the test class. - Declaration of
@BeforeAll
and@AfterAll
methods in@Nested
test classes. - Declaration of
@BeforeAll
and@AfterAll
on interface default methods. - Simplified declaration of
@BeforeAll
and@AfterAll
methods in test classes implemented with the Kotlin programming language.
See the test instance lifecycle documentation for further details.