JUnit Test Annotations and Lifecycle Callbacks
JUnit 5 annotations identify test methods and define code that runs before or after tests. Lifecycle callbacks such as `@BeforeAll` and `@AfterAll` run once per test class, while `@BeforeEach` and `@AfterEach` run around every test method.
`@Test` marks a method as a JUnit Jupiter test case. A test method normally has no arguments, returns `void`, and is an instance method; JUnit creates a test instance for each test method by default.
`@BeforeEach` runs before every `@Test`, and `@AfterEach` runs after every test. These callbacks are useful for resetting mutable state, preparing test data, or releasing resources that belong to one test execution.
`@BeforeAll` runs once before all tests in the class, while `@AfterAll` runs once after all tests have completed. With JUnit Jupiter's default per-method test-instance lifecycle, these methods must be `static`.
The required static modifier for `@BeforeAll` and `@AfterAll` can be avoided by configuring the class with `@TestInstance(TestInstance.Lifecycle.PER_CLASS)`. In that mode, JUnit uses one test instance for the class, so those lifecycle methods may be instance methods.
For a typical class, the lifecycle is conceptually `BeforeAll -> BeforeEach -> Test -> AfterEach` repeated for each test, followed by `AfterAll`. If multiple callbacks of the same type exist, their exact ordering should not be used as a substitute for explicit dependencies between setup steps.
Key points
- `@Test` identifies a test method.
- `@BeforeEach` and `@AfterEach` run around every test method.
- `@BeforeAll` and `@AfterAll` run once for the test class.
- With the default lifecycle, `@BeforeAll` and `@AfterAll` must be `static`.
- `@TestInstance(PER_CLASS)` permits non-static class-level lifecycle methods.
Interview questions
What is the difference between `@BeforeEach` and `@BeforeAll`?
`@BeforeEach` executes before every test method, so it is appropriate for state that each test needs independently. `@BeforeAll` executes once before the tests in the class, so it is useful for shared or expensive class-level initialization. Under the default JUnit Jupiter lifecycle, `@BeforeAll` must be static. With `PER_CLASS`, it can be an instance method.
What order do JUnit 5 lifecycle callbacks follow?
For a single test class, `@BeforeAll` runs before the individual tests begin. For each test, `@BeforeEach` runs before the test method and `@AfterEach` runs afterward. Once all tests finish, `@AfterAll` runs. Thus the common lifecycle can be remembered as class setup, per-test setup, test, per-test cleanup, and class cleanup.
Why are `@BeforeAll` and `@AfterAll` usually static?
JUnit Jupiter normally uses a separate test instance for each test method. A class-level callback needs to run before those instances are used and therefore cannot depend on a particular test instance under the default lifecycle. Making the callback static lets it operate at class scope. `@TestInstance(PER_CLASS)` changes this model and permits non-static class-level callbacks.
What should you put in `@BeforeEach`?
`@BeforeEach` should contain lightweight preparation that every test needs and that should be reset between tests. Typical examples include creating fresh objects, initializing test data, or resetting mocks. It should avoid unnecessary expensive work when that work can safely be performed once. Keeping setup isolated helps tests remain independent and easier to understand.
Can JUnit guarantee the order of test methods?
Tests should normally be written so that their correctness does not depend on another test having run first. JUnit Jupiter does not treat source-code order as a general contract for test execution. If a particular execution order is explicitly required, JUnit provides ordering mechanisms, but relying on ordering can increase coupling between tests. Independent tests are generally easier to maintain and run in isolation.