When writing automated tests, we often need to perform setup tasks before the tests run. This could involve initializing a database connection, starting a web server, or preparing a complex object that’s expensive to create. JUnit 5 provides a powerful set of annotations to manage the lifecycle of your tests, and for one-time setup logic, the @BeforeAll annotation is the perfect tool.
In this guide, we’ll take a deep dive into the @BeforeAll annotation, understand its rules, and explore its usage with practical code examples. We’ll also clarify the key difference between @BeforeAll and @BeforeEach.
@BeforeAll is the direct replacement for JUnit 4’s @BeforeClass annotation.
What is @BeforeAll?
The @BeforeAll annotation is used to signal that a method should be executed only once, before any tests in the current test class are run. It’s ideal for setup operations that are shared across all test methods in a class but are too resource-intensive to run before each and every test.
Core Rules for @BeforeAll Methods
To use @BeforeAll correctly, you need to follow a few simple rules:
- The annotated method must be a
staticmethod by default. - It must not return any value (i.e., its return type should be
void). - It cannot be a
privatemethod. It can bepublic,protected, or package-private.
The reason the method must be static is tied to JUnit 5’s default test instance lifecycle. By default, JUnit creates a new instance of the test class for every single test method. Since the @BeforeAll method runs before any of these instances are created, it must be associated with the class itself (as a static method) rather than a specific instance.
Example 1: Standard Usage with a Static Method
Let’s look at the most common way to use @BeforeAll. In this example, we’ll also use its counterpart, @AfterAll, which runs once after all tests in the class have completed. This is perfect for cleanup tasks like closing database connections or shutting down servers.
The Code
Here we have a simple test class with two test methods. The setupAll() method will run once before both tests, and teardownAll() will run once after both are finished.
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class StandardBeforeAllExampleTest {
@BeforeAll
static void setupAll() {
System.out.println("==> Executing setupAll()... (runs once)");
}
@Test
void testMethodOne() {
System.out.println("--> Executing testMethodOne()");
}
@Test
void testMethodTwo() {
System.out.println("--> Executing testMethodTwo()");
}
@AfterAll
static void teardownAll() {
System.out.println("==> Executing teardownAll()... (runs once)");
}
}
Execution Output
When you run this test class, you’ll see the following output, clearly showing the execution order:
==> Executing setupAll()... (runs once)
--> Executing testMethodOne()
--> Executing testMethodTwo()
==> Executing teardownAll()... (runs once)
As you can see, the setup and teardown methods were each executed only once, bookending the execution of the individual test methods.
Example 2: The Non-Static Alternative with @TestInstance
What if you don’t want to use static methods? Perhaps you want to initialize non-static instance fields in your setup method and use them across your tests. JUnit 5 provides a flexible solution for this: changing the test instance lifecycle.
By annotating your test class with @TestInstance(TestInstance.Lifecycle.PER_CLASS), you tell JUnit to create only a single instance of the test class and reuse it for all the test methods. Because there’s a single instance available from the beginning, your @BeforeAll and @AfterAll methods no longer need to be static.
The Code
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
// Change the test instance lifecycle to PER_CLASS
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class PerClassLifecycleExampleTest {
// This method can now be non-static
@BeforeAll
void setupAll() {
System.out.println("==> Executing setupAll() on a single instance...");
}
@Test
void testMethodOne() {
System.out.println("--> Executing testMethodOne()");
}
@Test
void testMethodTwo() {
System.out.println("--> Executing testMethodTwo()");
}
// This method can also be non-static
@AfterAll
void teardownAll() {
System.out.println("==> Executing teardownAll() on a single instance...");
}
}
Execution Output
The execution output is functionally identical, proving the lifecycle works as expected:
==> Executing setupAll() on a single instance...
--> Executing testMethodOne()
--> Executing testMethodTwo()
==> Executing teardownAll() on a single instance...
@BeforeAll vs. @BeforeEach
A common point of confusion for newcomers is the difference between @BeforeAll and @BeforeEach. The distinction is simple but critical for writing efficient tests.
| Feature | @BeforeAll | @BeforeEach |
|---|---|---|
| Execution Scope | Runs once per test class, before any tests start. | Runs before each and every @Test method in the class. |
| Method Signature | Must be static (unless @TestInstance(Lifecycle.PER_CLASS) is used). | Is typically a non-static instance method. |
| Common Use Case | Heavy, one-time setup: database connections, starting servers, initializing shared fixtures. | Lightweight setup or state reset: creating new mock objects, resetting variables to a default state before each test. |
Conclusion
The @BeforeAll annotation is an essential part of the JUnit 5 toolkit, enabling you to manage expensive setup operations efficiently. By understanding its core behavior and the flexibility offered by @TestInstance(Lifecycle.PER_CLASS), you can write cleaner, faster, and more maintainable tests.
Remember to use @BeforeAll for tasks that truly need to run only once per class and use @BeforeEach for resetting state between individual tests. Choosing the right tool for the job will significantly improve the quality of your test suite.