JUnit

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • JUnit is the industry-standard testing framework for Java.
  • JUnit 5 (Jupiter) is the current modern version, consisting of the Platform (runner), Jupiter (API), and Vintage (JUnit 4 backwards compatibility).
  • Tests are identified using the @Test annotation, and lifecycle is managed via @BeforeEach, @AfterEach, @BeforeAll, and @AfterAll.

Concept

To verify that your code works, you could just write a public static void main method, pass in some inputs, and print the outputs. However, this doesn’t scale. You need an automated way to run hundreds of tests instantly and get a clear pass/fail report.

JUnit provides the framework to do this. You write standard Java methods, annotate them with @Test, and use Assertions to verify that the output of your code matches the expected output. Build tools like Maven/Gradle automatically find these @Test methods, run them in isolation, and generate reports.

Examples

import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {

    private Calculator calc;

    // Runs ONCE before all tests (must be static)
    @BeforeAll
    static void initAll() {
        System.out.println("Starting test suite...");
    }

    // Runs before EVERY individual test
    @BeforeEach
    void setUp() {
        calc = new Calculator(); 
    }

    // The actual test method
    @Test
    @DisplayName("1 + 1 should equal 2")
    void testAddition() {
        int result = calc.add(1, 1);
        assertEquals(2, result, "Addition logic failed");
    }

    // Testing Exceptions
    @Test
    void testDivisionByZero() {
        Exception exception = assertThrows(ArithmeticException.class, () -> {
            calc.divide(10, 0);
        });
        assertEquals("/ by zero", exception.getMessage());
    }

    // Runs after EVERY individual test
    @AfterEach
    void tearDown() {
        calc = null; // Cleanup
    }
}

Interview Questions

Q: What is the difference between @BeforeEach and @BeforeAll?
A: - @BeforeEach (JUnit 5) or @Before (JUnit 4) runs before every single @Test method. It is used to set up a fresh environment or instantiate fresh objects for each test to ensure tests do not bleed state into each other.

  • @BeforeAll (JUnit 5) or @BeforeClass (JUnit 4) runs exactly once before any tests in the class run. It must be a static method. It is used for expensive setups, like opening a database connection or spinning up a test container, which all tests will share.

Q: Why does JUnit create a new instance of the Test Class for every test method?
A: By default, if you have 5 @Test methods in CalculatorTest, JUnit actually creates 5 separate instances of the CalculatorTest class. It does this to guarantee Test Isolation. If one test accidentally mutates a class-level variable, it won’t affect the next test, preventing flaky tests that randomly pass or fail depending on execution order. (You can change this behavior in JUnit 5 using @TestInstance(Lifecycle.PER_CLASS)).