# Lifecycle, Nested Tests, Tags and Display Names — JUnit 5 & Mockito

Source: https://www.skillbyai.com/en/java-testing/j-lifecycle

> Use lifecycle methods, test instance lifecycle, @Nested, @Tag and @Disabled.

## Organising and setting up tests

**Lifecycle methods** run around tests: **`@BeforeEach`** and **`@AfterEach`** before and after every test method, **`@BeforeAll`** and **`@AfterAll`** once per class (they must be `static` unless the class uses `@TestInstance(Lifecycle.PER_CLASS)`). By default JUnit creates a **new instance of the test class for every test method** (`PER_METHOD`), so instance fields are fresh each time and tests cannot leak state through them. **`@Nested`** inner classes group related tests with their own setup, producing readable hierarchies such as "Wallet / when empty / pay throws". **`@DisplayName`** gives readable names, and a `@DisplayNameGeneration` strategy can derive them from method names. **`@Tag("slow")`** labels tests so builds can include or exclude groups (for example running only fast tests on each commit). **`@Disabled("reason")`** skips a test, but always give a reason and a ticket, otherwise disabled tests rot forever. **`@RepeatedTest(n)`** runs a test several times, useful for spotting flakiness.

## Nested structure with shared setup

Each nested class adds its own context to the outer setup.

```java
@DisplayName("Shopping cart")
class CartTest {

    private Cart cart;

    @BeforeEach
    void createCart() {
        cart = new Cart();                     // fresh for every test (PER_METHOD lifecycle)
    }

    @Nested
    @DisplayName("when empty")
    class WhenEmpty {
        @Test
        @DisplayName("total is zero")
        void totalIsZero() { assertThat(cart.totalPaise()).isZero(); }

        @Test
        @DisplayName("checkout is rejected")
        void checkoutRejected() { assertThatThrownBy(cart::checkout).isInstanceOf(IllegalStateException.class); }
    }

    @Nested
    @DisplayName("with two items")
    class WithTwoItems {
        @BeforeEach
        void addItems() {
            cart.add("pen", 2, 4_950);
            cart.add("ink", 1, 12_000);
        }

        @Test
        void totalSumsLines() { assertThat(cart.totalPaise()).isEqualTo(21_900); }

        @Test
        @Tag("slow")
        void checkoutCreatesOrder() { assertThat(cart.checkout().lines()).hasSize(2); }
    }
}
```

## Chapters and sections in a manual

Nested test classes are like a manual's chapters and sections: "Cart → when empty → total is zero". Readers find the rule they care about without scanning one long, flat list.

**Quiz:** By default, how many test-class instances does JUnit Jupiter create for a class with five test methods?

- [ ] One shared instance
- [x] Five, one per test method
- [ ] Two
- [ ] None; tests are static

*Answer:* Five, one per test method. The default PER_METHOD lifecycle creates a fresh instance for each test method.
