src/
└── test/
└── java/
└── com/
└── example/
├── pages/
│ └── LoginPage.java
├── tests/
│ └── LoginTest.java
├── utils/
│ └── TestUtils.java
└── config/
└── TestConfig.java
Why lifecycle hooks manage setup and teardown in JUnit - Framework Benefits
- Driver Layer: Manages WebDriver setup and teardown for browser control.
- Page Objects: Encapsulate UI elements and actions for each page.
- Tests: Contain test methods using JUnit annotations and lifecycle hooks.
- Utilities: Helper methods for common tasks like waits or data handling.
- Configuration: Holds environment settings, credentials, and browser options.
Use @BeforeAll and @AfterAll for global setup and teardown, like starting/stopping WebDriver once per test class.
Use @BeforeEach and @AfterEach for setup and cleanup before and after each test method, such as navigating to a page or clearing cookies.
Store environment variables and credentials in TestConfig.java or external files, loaded at runtime.
Configure browser type and options via system properties or config files to allow flexible test runs.
JUnit integrates with build tools like Maven or Gradle to generate reports in XML or HTML formats.
CI/CD pipelines (e.g., Jenkins, GitHub Actions) run tests automatically on code changes and publish reports.
Lifecycle hooks ensure tests start with a clean state and resources are released, preventing flaky tests and resource leaks in CI environments.
- Use lifecycle hooks to avoid code duplication: Setup and teardown code is centralized, making tests cleaner.
- Keep setup fast and minimal: Only initialize what is necessary to reduce test execution time.
- Ensure teardown cleans resources: Close browsers and clear data to prevent interference between tests.
- Use
@BeforeAlland@AfterAllfor expensive operations: Like starting a database connection once per test class. - Write independent tests: Lifecycle hooks help tests run independently by resetting state before each test.
In the folder structure shown, where would you add a new @BeforeEach method to open the browser before each test?
Practice
@BeforeEach and @AfterEach in JUnit tests?Solution
Step 1: Understand lifecycle hooks purpose
Lifecycle hooks like@BeforeEachand@AfterEachrun code before and after each test method to prepare and clean up the test environment.Step 2: Identify correct use case
This avoids repeating setup and teardown code inside every test, keeping tests clean and consistent.Final Answer:
To run setup and cleanup code before and after each test automatically -> Option BQuick Check:
Lifecycle hooks = setup/teardown automation [OK]
- Thinking lifecycle hooks skip assertions
- Confusing lifecycle hooks with parallel test execution
- Assuming lifecycle hooks generate reports
Solution
Step 1: Identify the annotation for running once before all tests
The@BeforeAllannotation runs a method once before any tests in the class run.Step 2: Check method signature requirements
Methods with@BeforeAllmust be static in JUnit 5, sopublic static void init()is correct.Final Answer:
@BeforeAll public static void init() {} -> Option CQuick Check:
@BeforeAll + static = run once before all tests [OK]
- Using @BeforeEach instead of @BeforeAll for once-only setup
- Not making @BeforeAll method static
- Confusing @AfterEach with setup annotations
class SampleTest {
static int counter = 0;
@BeforeEach
void beforeEach() {
counter++;
}
@Test
void testOne() {}
@Test
void testTwo() {}
@AfterAll
static void afterAll() {
System.out.println(counter);
}
}What will be printed when the tests run?
Solution
Step 1: Analyze the lifecycle annotations and method signatures
The@AfterAllmethod must be static, which it is. However,counteris static and incremented in@BeforeEachwhich is non-static, so no issue there.Step 2: Check for JUnit 5 rules on lifecycle methods
JUnit 5 requires@BeforeEachand@AfterEachmethods to be non-static, which is correct here. But@AfterAllis static, so no problem.Step 3: Identify the problem
However, the class is missing the@TestInstance(Lifecycle.PER_CLASS)annotation if we want to use static fields properly with lifecycle hooks. Without it, static fields are fine but the test runner may not allow static@AfterAllwithout this annotation in some setups.Step 4: Confirm if code compiles
Actually, this code compiles and runs fine. The counter increments twice (once per test), so2is printed.Final Answer:
2 -> Option AQuick Check:
Counter increments twice = 2 printed [OK]
- Assuming @AfterAll cannot access static fields
- Thinking counter resets between tests
- Confusing static and instance method requirements
class TestExample {
@BeforeAll
void setup() {
System.out.println("Setup");
}
@Test
void test() {
System.out.println("Test running");
}
}Solution
Step 1: Check @BeforeAll method requirements
In JUnit 5, methods annotated with@BeforeAllmust be static unless the test class is annotated with@TestInstance(Lifecycle.PER_CLASS).Step 2: Verify method signature
Thesetup()method is not static, and the class lacks@TestInstance, so this causes a runtime error.Final Answer:
Method annotated with @BeforeAll must be static -> Option AQuick Check:
@BeforeAll requires static method without @TestInstance [OK]
- Thinking @Test methods must be static
- Believing missing @AfterEach is an error
- Ignoring static requirement for @BeforeAll
Solution
Step 1: Understand resource management scope
Opening a database connection once before all tests and closing it once after all tests saves time and resources.Step 2: Choose correct lifecycle hooks
@BeforeAlland@AfterAllrun once per test class, ideal for this purpose. They must be static methods unless using@TestInstance(Lifecycle.PER_CLASS).Final Answer:
Use @BeforeAll static method to open and @AfterAll static method to close the connection -> Option DQuick Check:
Open/close once with @BeforeAll/@AfterAll static methods [OK]
- Using @BeforeEach/@AfterEach causing repeated open/close
- Opening/closing inside each test wastes resources
- Using non-static @BeforeAll/@AfterAll without @TestInstance
Ready to prove it?
Pass the test and this pattern moves unknown
