Cosmic Module

J

Qubits of DPK

March 14, 2026

Core Java

Layman Explanation

When you build a bridge, engineers test every bolt before assembling. JUnit is Java's testing framework — you write small automated tests that verify each method works correctly, so bugs are caught early before they reach production.

What is JUnit 5?

JUnit 5 is the standard testing framework for Java. It lets you write automated unit tests that verify your code behaves correctly.
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

Basic Test Structure

java
QUBITS OF DPK
1import org.junit.jupiter.api.*;
2import static org.junit.jupiter.api.Assertions.*;
3
4class CalculatorTest {
5
6    Calculator calc;
7
8    @BeforeEach
9    void setUp() {
10        calc = new Calculator();   // runs before EACH test
11    }
12
13    @AfterEach
14    void tearDown() {
15        // runs after EACH test
16    }
17
18    @BeforeAll
19    static void init() {
20        // runs ONCE before all tests
21    }
22
23    @AfterAll
24    static void cleanup() {
25        // runs ONCE after all tests
26    }
27
28    @Test
29    void testAddition() {
30        int result = calc.add(5, 3);
31        assertEquals(8, result);   // expected, actual
32    }
33
34    @Test
35    void testDivisionByZero() {
36        assertThrows(ArithmeticException.class, () -> {
37            calc.divide(10, 0);
38        });
39    }
40
41    @Test
42    @Disabled("Not implemented yet")
43    void testSquareRoot() {
44        // skipped
45    }
46}

Key Annotations

javascript
QUBITS OF DPK
1@Test              → marks a test method
2@BeforeEach        → runs before each test method
3@AfterEach         → runs after each test method
4@BeforeAll         → runs once before all tests (static)
5@AfterAll          → runs once after all tests (static)
6@Disabled          → skip this test
7@DisplayName       → custom test name
8@RepeatedTest(5)   → run test 5 times
9@ParameterizedTest → run with different inputs

Common Assertions

java
QUBITS OF DPK
1// Equality
2assertEquals(expected, actual);
3assertNotEquals(unexpected, actual);
4
5// Null checks
6assertNull(object);
7assertNotNull(object);
8
9// Boolean
10assertTrue(condition);
11assertFalse(condition);
12
13// Exceptions
14assertThrows(ExceptionClass.class, () -> riskMethod());
15
16// Arrays/Collections
17assertArrayEquals(expectedArr, actualArr);
18
19// All with custom message
20assertEquals(8, result, "Addition should return 8");
21
22// Group assertions (all run even if one fails)
23assertAll(
24    () -> assertEquals(8, calc.add(5,3)),
25    () -> assertEquals(2, calc.subtract(5,3)),
26    () -> assertEquals(15, calc.multiply(5,3))
27);

Parameterized Tests

java
QUBITS OF DPK
1@ParameterizedTest
2@ValueSource(ints = {2, 4, 6, 8, 10})
3void testEvenNumbers(int number) {
4    assertTrue(number % 2 == 0);
5}
6
7@ParameterizedTest
8@CsvSource({
9    "5, 3, 8",
10    "10, 20, 30",
11    "0, 0, 0"
12})
13void testAddition(int a, int b, int expected) {
14    assertEquals(expected, calc.add(a, b));
15}

Test Lifecycle

javascript
QUBITS OF DPK
1@BeforeAll (once)
23    ├── @BeforeEach → @Test(testAddition) → @AfterEach
4    ├── @BeforeEach → @Test(testSubtract) → @AfterEach
5    ├── @BeforeEach → @Test(testMultiply) → @AfterEach
67@AfterAll (once)

Production Use Cases

java
QUBITS OF DPK
1// Testing a service class
2class PaymentServiceTest {
3
4    @Test
5    @DisplayName("Should throw exception for negative amount")
6    void shouldRejectNegativeAmount() {
7        PaymentService service = new PaymentService();
8        assertThrows(IllegalArgumentException.class,
9            () -> service.processPayment(-100.0));
10    }
11
12    @Test
13    @DisplayName("Should return transaction ID for valid payment")
14    void shouldReturnTransactionId() {
15        PaymentService service = new PaymentService();
16        String txnId = service.processPayment(500.0);
17        assertNotNull(txnId);
18        assertTrue(txnId.startsWith("TXN"));
19    }
20}

️ Traps

java
QUBITS OF DPK
1// Trap 1 — assertEquals order matters for error messages
2assertEquals(expected, actual);  // ✅ correct order
3assertEquals(actual, expected);  // ⚠️ works but error message is misleading
4
5// Trap 2 — @BeforeAll must be static
6@BeforeAll
7void init() { }         // ❌ must be static!
8@BeforeAll
9static void init() { }  // ✅
10
11// Trap 3 — Test method must be void and non-private
12private void testAdd() { }  // ❌ JUnit can't see private!
13void testAdd() { }          // ✅
14
15// Trap 4 — assertThrows doesn't catch outside lambda
16assertThrows(Exception.class, () -> {
17    // exception must be thrown INSIDE this lambda
18});

30-Second Interview Answer

"JUnit 5 is Java's standard unit testing framework. Tests are annotated with @Test, lifecycle methods with @BeforeEach/@AfterEach for per-test setup/teardown, and @BeforeAll/@AfterAll for one-time setup. Assertions like assertEquals, assertThrows, assertAll verify expected behavior. Parameterized tests run the same test with multiple inputs. Key principles: test one thing per method, use descriptive @DisplayName, test both happy path and edge cases. TDD (Test Driven Development) writes tests before implementation."

Interview Questions & MAANG-Level Answers

Q1. What is JUnit 5 and why is testing important?
JUnit 5 is Java's standard unit testing framework consisting of JUnit Platform (launcher), JUnit Jupiter (new API), and JUnit Vintage (legacy support). Testing importance: (1) Catches bugs early — fix at development, not production. (2) Enables refactoring — change code confidently with test safety net. (3) Documents behavior — tests show how code is supposed to work. (4) CI/CD gates — tests run automatically on every commit, blocking broken code from merging. At MAANG, code without tests is not accepted in PRs.
Q2. What is the difference between @BeforeEach and @BeforeAll?
@BeforeEach: runs before EACH individual test method — use for per-test setup like creating a fresh object. @BeforeAll: runs ONCE before ALL test methods in the class — must be static (JUnit creates one instance per class). Use for expensive one-time setup like starting a test database or loading a large file:
java
QUBITS OF DPK
1@BeforeAll static void initDatabase() { /* expensive, runs once */ }
2@BeforeEach void resetState() { calculator = new Calculator(); /* fresh per test */ }
Mirror annotations: @AfterEach (cleanup per test), @AfterAll (one-time cleanup).
Q3. How do you test that a method throws an exception?
Use assertThrows() which takes the expected exception class and a lambda:
java
QUBITS OF DPK
1@Test
2void shouldThrowForNegativeAmount() {
3    PaymentService service = new PaymentService();
4    IllegalArgumentException ex = assertThrows(
5        IllegalArgumentException.class,
6        () -> service.processPayment(-100.0)
7    );
8    assertEquals("Amount must be positive", ex.getMessage());  // verify message too
9}
The lambda must throw the exception — if it doesn't, the test fails. You can also assert on the exception's message or properties.
Q4. What is a parameterized test?
A parameterized test runs the same test method with multiple different inputs, avoiding duplicated test code:
java
QUBITS OF DPK
1@ParameterizedTest
2@CsvSource({"5,3,8", "10,20,30", "0,0,0", "-5,5,0"})
3void testAddition(int a, int b, int expected) {
4    assertEquals(expected, calculator.add(a, b));
5}
Sources: @ValueSource (single values), @CsvSource (multiple fields), @MethodSource (from a method), @EnumSource (enum values). Greatly reduces test code and ensures edge cases are covered systematically.
Q5. What is TDD (Test Driven Development)?
TDD is a development approach where you write tests BEFORE writing the implementation. Red-Green-Refactor cycle: (1) Red — write a failing test for the feature. (2) Green — write minimum code to make the test pass. (3) Refactor — improve code quality while keeping tests green. Benefits: forces you to think about the API before implementation, results in 100% test coverage by design, and leads to simpler, more testable code. At MAANG, TDD is encouraged, especially for core business logic.
Q6. What is the difference between unit tests and integration tests?
Unit tests: test a single class/method in isolation, mock all dependencies, very fast (milliseconds), no external systems. Example: test Calculator.add() in isolation. Integration tests: test multiple components working together, use real databases/HTTP clients/message queues, slower (seconds), reveal integration issues. Example: test PaymentController making real DB call. In CI/CD: unit tests run on every commit (fast), integration tests run less frequently (nightly or pre-merge). Rule of thumb: 70% unit, 20% integration, 10% end-to-end (testing pyramid).