yoklainterview sim

Backend Java Testing Tooling Interview Questions

75 verified Backend Java Testing Tooling interview questions — solve with answers, learn from explanations, test yourself in a real simulation.

Try the real simulation →

Sample questions

Java Testing ToolingDifficulty 1
In JUnit 5, what is required for a method to be picked up and run as a test by the test runner?
  • aThe method name must start with the word test, since JUnit 5 still relies on naming conventions like JUnit 3 did
  • bThe method must be annotated with @Test (or a related test-registering annotation such as @ParameterizedTest)
  • cThe method must be declared public static so the runner can invoke it without creating a test instance
  • dThe class must implement a Testable interface that exposes the method to the JUnit 5 discovery engine
Explanation:JUnit 5 discovers tests purely through annotations, not naming conventions. A method annotated with @Test (or @ParameterizedTest, @RepeatedTest, etc.) is registered as a test. There is no required method name prefix, no public static requirement (instance methods are used, package-private is enough), and no Testable interface to implement.
Java Testing ToolingDifficulty 2
class CounterTest {
    int count;

    @BeforeEach
    void setUp() {
        count = 10;
        System.out.println("setUp");
    }

    @Test
    void increments() {
        count++;
        System.out.println("test:" + count);
    }

    @AfterEach
    void tearDown() {
        System.out.println("tearDown:" + count);
    }
}

What is printed when increments() runs?
  • asetUp, test:11, tearDown:11 — because @BeforeEach runs before the test and @AfterEach runs after, using the same instance state
  • btest:11, setUp, tearDown:10 — because JUnit runs the annotated test method first and only wires lifecycle hooks around it afterward for cleanup
  • csetUp, test:11, tearDown:0 — because @AfterEach runs on a freshly re-initialized field before it prints
  • dsetUp, tearDown:10, test:11 — because @AfterEach restores the field to its pre-test value before printing it
Explanation:For each @Test method, JUnit 5 runs @BeforeEach first, then the test itself, then @AfterEach — all on the SAME test instance, so field state carries over between them. setUp sets count = 10 and prints setUp. The test increments to 11 and prints test:11. tearDown then prints the current count, which is still 11, giving tearDown:11.
Java Testing ToolingDifficulty 2
@Test
void checksTotal() {
    int actualTotal = computeTotal(); // returns 7
    assertEquals(actualTotal, 10);
}

The test fails. What does the failure message report?
  • a"expected: <7> but was: <10>" — because the first argument passed to assertEquals is treated as expected, and here actualTotal (7) was passed first by mistake
  • b"expected: <10> but was: <7>" — because JUnit always labels the smaller numeric value as the actual result regardless of argument order, inferring intent from the values themselves rather than their position
  • cA compile error, because assertEquals requires the literal expected value to be passed as the second argument
  • d"expected: <10> but was: <10>" — because JUnit resolves both arguments to the same comparison target before reporting them
Explanation:assertEquals(expected, actual) treats its FIRST argument as "expected" and the SECOND as "actual", purely by position — it has no idea which variable name means what. Here the call is assertEquals(actualTotal, 10), so JUnit reports actualTotal (7) as expected and 10 as actual: "expected: <7> but was: <10>". This is a common junior mistake — the arguments are swapped, which doesn't change whether the test passes/fails but does produce a misleading message.
Java Testing ToolingDifficulty 2
@Test
void rejectsNegativeAmount() {
    Account acc = new Account();
    IllegalArgumentException ex = assertThrows(
        IllegalArgumentException.class,
        () -> acc.withdraw(-5)
    );
    assertEquals("amount must be positive", ex.getMessage());
}

What does assertThrows return here, and why is that useful?
  • aIt returns void; ex is actually assigned by a hidden static field that JUnit's internal reporting mechanism populates only after the whole lambda has finished running, which the test then reads back
  • bIt returns a boolean indicating whether the exception was thrown, and ex is auto-cast to the exception type for convenience
  • cIt returns the lambda (Executable) itself, letting the test re-invoke acc.withdraw(-5) again to inspect the exception
  • dIt returns the caught exception instance (typed as IllegalArgumentException), letting the test make further assertions on its state such as the message
Explanation:assertThrows(expectedType, executable) runs the executable, asserts that it throws an exception assignable to expectedType, and returns that caught exception (already cast to expectedType). This lets the test go beyond "an exception was thrown" and assert on details like ex.getMessage() or ex.getCause(). If no exception is thrown, or the wrong type is thrown, assertThrows itself fails the test.
Java Testing ToolingDifficulty 1
@Test
void parsesConfig() {
    Config c = Config.parse("invalid"); // throws NumberFormatException internally
    assertNotNull(c);
}

If Config.parse("invalid") throws an unchecked NumberFormatException that the test does not catch, what happens to the test?
  • aThe test passes, because JUnit only evaluates the final assertNotNull statement in a test method and never reaches an exception thrown by earlier lines before it
  • bThe test fails/errors, because any uncaught exception propagating out of a @Test method is reported as a test failure
  • cThe test is skipped, because JUnit treats uncaught runtime exceptions the same way it treats @Disabled
  • dThe build stops immediately and no other test methods in the class or suite are executed
Explanation:A @Test method does not need assertThrows to fail on an exception — ANY exception (checked or unchecked) that propagates out of the test method is caught by the JUnit runner and reported as a failed/errored test. It never reaches assertNotNull in this case. Other tests in the class and suite still run; JUnit isolates failures per test method.
Java Testing ToolingDifficulty 2
interface PaymentGateway {
    boolean charge(String cardId, int amountCents);
    String lastTransactionId();
}

@Test
void unstubbedMockReturnsDefaults() {
    PaymentGateway gw = mock(PaymentGateway.class);

    boolean result = gw.charge("card-1", 500);
    String txId = gw.lastTransactionId();

    assertFalse(result);
    assertNull(txId);
}

Without any when(...).thenReturn(...) stubbing, why does this test pass?
  • aIt doesn't pass — calling any method on a Mockito mock without stubbing throws UnnecessaryStubbingException at runtime
  • bMockito records the calls but replays the real PaymentGateway implementation found on the classpath, which happens to return false/null for these inputs
  • cA Mockito mock returns type-appropriate default values for unstubbed methods — false for boolean, null for object return types, 0 for numeric types
  • dThe mock throws a NullPointerException on the first unstubbed call, which the test framework silently converts into a passing assertion
Explanation:A Mockito mock created with mock(...) has NO real behavior by default. For any method call that hasn't been stubbed with when(...).thenReturn(...), Mockito returns a sensible default based on the return type: false for boolean, 0/0.0 for numeric primitives, null for object references (including String), and empty collections for collection return types. No exception is thrown just for calling an unstubbed method.

Test yourself against the 3300-question Backend bank.

Start interview