Test fixtures help set up the environment before tests run and clean up after. This makes tests reliable and easy to manage.
Test fixtures and lifecycle in Kotlin
import org.junit.jupiter.api.* @TestInstance(TestInstance.Lifecycle.PER_CLASS) class MyTests { @BeforeAll fun setupAll() { // Runs once before all tests } @BeforeEach fun setup() { // Runs before each test } @Test fun testExample() { // Test code here } @AfterEach fun tearDown() { // Runs after each test } @AfterAll fun tearDownAll() { // Runs once after all tests } }
@BeforeAll and @AfterAll methods run once for the whole test class.
@BeforeEach and @AfterEach run before and after every single test method.
import org.junit.jupiter.api.* class SimpleTest { @BeforeEach fun prepare() { println("Setup before each test") } @Test fun testOne() { println("Running test one") } @Test fun testTwo() { println("Running test two") } @AfterEach fun cleanup() { println("Cleanup after each test") } }
import org.junit.jupiter.api.* @TestInstance(TestInstance.Lifecycle.PER_CLASS) class ClassLevelTest { @BeforeAll fun initAll() { println("Setup once before all tests") } @AfterAll fun cleanupAll() { println("Cleanup once after all tests") } @Test fun testA() { println("Test A running") } @Test fun testB() { println("Test B running") } }
This program shows a simple Calculator test class. It creates a Calculator before each test and clears it after. It prints messages to show the test lifecycle.
import org.junit.jupiter.api.* @TestInstance(TestInstance.Lifecycle.PER_CLASS) class CalculatorTest { private var calculator: Calculator? = null @BeforeAll fun setupAll() { println("Starting Calculator tests") } @BeforeEach fun setup() { calculator = Calculator() println("Calculator created") } @Test fun testAdd() { val result = calculator?.add(2, 3) println("Add result: $result") Assertions.assertEquals(5, result) } @AfterEach fun tearDown() { calculator = null println("Calculator cleared") } @AfterAll fun tearDownAll() { println("Finished Calculator tests") } } class Calculator { fun add(a: Int, b: Int): Int = a + b }
Use @BeforeAll and @AfterAll for expensive setup or cleanup done once.
Use @BeforeEach and @AfterEach to prepare fresh state for every test.
Remember to annotate the test class with @TestInstance(TestInstance.Lifecycle.PER_CLASS) if you want non-static @BeforeAll and @AfterAll methods.
Test fixtures prepare and clean the test environment.
@BeforeAll/@AfterAll run once per class; @BeforeEach/@AfterEach run per test.
They help keep tests independent and easy to maintain.
Practice
Solution
Step 1: Understand what test fixtures do
Test fixtures set up the environment needed for tests and clean it afterward to avoid side effects.Step 2: Identify the correct purpose
Among the options, only preparing and cleaning the test environment matches the role of test fixtures.Final Answer:
To prepare and clean the test environment before and after tests -> Option AQuick Check:
Test fixtures = prepare and clean environment [OK]
- Confusing fixtures with test case logic
- Thinking fixtures generate test data
- Assuming fixtures compile code
Solution
Step 1: Recall lifecycle annotations
@BeforeAll runs once before all tests; @BeforeEach runs before each test.Step 2: Match annotation to description
The annotation that runs once before all tests is @BeforeAll.Final Answer:
@BeforeAll -> Option BQuick Check:
@BeforeAll = run once before all tests [OK]
- Mixing @BeforeEach with @BeforeAll
- Confusing @AfterAll with @BeforeAll
- Using @AfterEach instead of @BeforeAll
class SampleTest {
@BeforeAll
fun setupAll() = println("SetupAll")
@BeforeEach
fun setup() = println("Setup")
@Test
fun test1() = println("Test1")
@Test
fun test2() = println("Test2")
@AfterEach
fun tearDown() = println("TearDown")
@AfterAll
fun tearDownAll() = println("TearDownAll")
}Solution
Step 1: Understand lifecycle order
@BeforeAll runs once before all tests, then for each test @BeforeEach, test, @AfterEach run, and finally @AfterAll runs once after all tests.Step 2: Trace the print statements
Output order: SetupAll (once), then for test1: Setup, Test1, TearDown; for test2: Setup, Test2, TearDown; finally TearDownAll.Final Answer:
SetupAll Setup Test1 TearDown Setup Test2 TearDown TearDownAll -> Option DQuick Check:
Lifecycle order = D [OK]
- Assuming @BeforeEach runs once only
- Mixing order of AfterEach and AfterAll
- Forgetting @BeforeAll and @AfterAll run once
@BeforeAll
fun setup() {
println("Setup")
}
@Test
fun testExample() {
println("Test")
}Solution
Step 1: Recall @BeforeAll requirements in Kotlin
@BeforeAll methods must be static or placed inside a companion object to run once before all tests.Step 2: Check the code snippet
The setup() method is annotated with @BeforeAll but is not static nor inside a companion object, causing an error.Final Answer:
@BeforeAll method must be static or inside a companion object -> Option AQuick Check:
@BeforeAll requires static or companion object [OK]
- Thinking @BeforeAll can be a normal instance method
- Assuming test methods must be private
- Believing setup() needs a return value
Solution
Step 1: Understand lifecycle for shared resources
Resources like database connections should open once before all tests and close once after all tests to save time and avoid repeated setup.Step 2: Apply Kotlin @BeforeAll/@AfterAll rules
In Kotlin, @BeforeAll and @AfterAll must be inside a companion object or be static to run once per class.Step 3: Evaluate options
Use @BeforeAll inside a companion object to open and @AfterAll inside the companion object to close correctly uses @BeforeAll and @AfterAll inside a companion object for one-time setup and teardown.Final Answer:
Use @BeforeAll inside a companion object to open and @AfterAll inside the companion object to close -> Option CQuick Check:
Shared setup/teardown = @BeforeAll/@AfterAll in companion object [OK]
- Using @BeforeEach/@AfterEach for expensive shared setup
- Placing @BeforeAll/@AfterAll outside companion object
- Opening connection in constructor instead of fixture
Ready to prove it?
Pass the test and this pattern moves unknown
