skip to content

Testing

The JVM testing toolchain: JUnit 5 for writing and running tests, Mockito for isolating collaborators, AssertJ and Hamcrest for expressive assertions, and JaCoCo for coverage. Interviewers expect fluency with these because they are what you would use on day one.

part ofJavaoverview, primer and where to startread it →
on this pageshow

explore

questions

132 · 5 sections

How do you write a basic unit test in JUnit 5, and what do the core annotations (@Test, @BeforeEach, @AfterEach, @BeforeAll, @AfterAll) do?

level: juniorimportance: must knowfreq 85%
basics
~10 s

A unit test is a method marked @Test that checks one behavior using assertions like assertEquals. @BeforeEach/@AfterEach run setup/cleanup before and after every test; @BeforeAll/@AfterAll run once for the whole class.

open as a page

Using Mockito, how do test doubles map to stubbing (when/thenReturn) versus verification (verify), and how does this relate to the dummy/fake/stub/spy/mock taxonomy?

level: middleimportance: must knowfreq 78%
basics
~20 s

Mockito creates fake versions of dependencies. when(x).thenReturn(y) sets up canned answers (stubbing — controlling input). verify(x).method() checks that your code actually called a dependency (verification — checking interactions). Stubs feed data in; mocks confirm behavior.

open as a page

Compare assertion styles in Java tests: built-in JUnit assertions vs AssertJ vs Hamcrest. When would you choose each?

level: middleimportance: should knowfreq 60%
basics
~10 s

JUnit's assertEquals is fine for simple checks. AssertJ gives fluent, chainable assertions like assertThat(list).contains(x) with great readability and IDE autocomplete. Hamcrest uses matcher objects like assertThat(x, is(5)). AssertJ is the modern default.

open as a page

How do you practice red-green-refactor TDD in Java with JUnit 5, and how do parameterized tests (@ParameterizedTest) support data-driven test design?

level: middleimportance: should knowfreq 55%
basics
~20 s

TDD: write a failing test first (red), write just enough code to pass (green), then clean up the code (refactor), repeating in small loops. JUnit's @ParameterizedTest runs the same test logic over many input sets (via @ValueSource, @CsvSource, @MethodSource) instead of copy-pasting tests.

open as a page

How does the testing pyramid map onto a typical Java/Spring stack, and what causes flaky tests in this context?

level: seniorimportance: should knowfreq 58%
basics
~20 s

The pyramid says: many fast unit tests (plain JUnit + Mockito), fewer integration tests (@SpringBootTest, Testcontainers), and very few slow end-to-end tests. Flaky tests pass and fail without code changes, often due to timing, shared state, real time/randomness, or test ordering.

open as a page

What is JUnit 5's assertAll, and what problem does it solve compared to writing several separate assertions?

level: juniorimportance: must knowfreq 55%
basics
~20 s

assertAll runs a group of assertions together and reports every failure at once. With plain asserts, the test stops at the first failure, so you only see one problem. assertAll shows all of them in one run.

open as a page

In JUnit 5's assertEquals, what is the argument order, and why does getting it wrong matter?

level: juniorimportance: must knowfreq 70%
basics
~20 s

The order is assertEquals(expected, actual). The first value is what you expect, the second is what your code produced. Swapping them still passes or fails correctly, but the failure message reads backwards and confuses you.

open as a page

What is JUnit 5's assertThrows and how do you use it to verify that code throws an expected exception?

level: juniorimportance: must knowfreq 78%
basics
~20 s

assertThrows runs a piece of code and checks it throws the exception type you expect. You pass the expected exception class and a lambda holding the code. The test passes only if that code throws that type (or a subtype).

open as a page

In JUnit 5, what is the difference between an assumption (assumeTrue) and an assertion (assertTrue)? What happens to a test when each one fails?

level: juniorimportance: must knowfreq 55%
basics
~20 s

An assertion checks the result you are testing: if it is false, the test FAILS. An assumption checks a precondition: if it is false, the test is SKIPPED (aborted), not failed. So a failed assumption is treated like a test that did not run.

open as a page

What do @BeforeAll and @AfterAll do in JUnit 5, and how do they differ from @BeforeEach and @AfterEach?

level: juniorimportance: must knowfreq 70%
basics
~10 s

@BeforeAll runs once before all the tests in a class; @AfterAll runs once after all of them. @BeforeEach and @AfterEach run before and after every single test method instead.

open as a page

What is Mockito's ArgumentCaptor and what problem does it solve?

level: juniorimportance: must knowfreq 70%
basics
~10 s

ArgumentCaptor catches the actual value passed to a mock's method so you can store it and check it afterward with normal assertions, instead of only checking that the method was called.

open as a page

What are argument matchers in Mockito, and why would you use any() or eq() instead of passing a literal value when stubbing or verifying?

level: juniorimportance: must knowfreq 70%
basics
~20 s

Argument matchers like any() or eq() tell Mockito how to match the arguments of a call instead of comparing exact values. Use any() when the value doesn't matter and eq(x) when you need a specific value but other arguments use matchers.

open as a page

What do the Mockito @Mock and @InjectMocks annotations do, and how do they work together in a unit test?

level: juniorimportance: must knowfreq 80%
basics
~10 s

@Mock creates a fake stand-in for a dependency. @InjectMocks creates the real object you are testing and pushes those mocks into it, so you can test it in isolation without its real collaborators.

open as a page

What does a freshly created, unstubbed Mockito mock return when its methods are called, for various return types?

level: juniorimportance: must knowfreq 75%
basics
~20 s

An unstubbed mock returns safe empty defaults: null for objects, 0 for numbers, false for booleans, and empty collections (an empty list/set/map, not null). So calling a method you didn't stub won't throw on its own.

open as a page

What is a mock object in Mockito, how do you create one, and why would you use it in a unit test?

level: juniorimportance: must knowfreq 85%
basics
~20 s

A mock is a fake stand-in for a real object that you create with Mockito.mock(SomeClass.class). You use it to replace a real collaborator so your test exercises only the one class you care about, without its dependencies doing real work.

open as a page

What is AssertJ and how does its fluent assertThat(...) style differ from JUnit's assertEquals or Hamcrest's assertThat?

level: juniorimportance: must knowfreq 70%
basics
~20 s

AssertJ is a Java assertion library. You write assertThat(actual) then chain readable checks like .isEqualTo(expected) or .isNotNull(). It reads left-to-right (actual first) and gives clear failure messages, unlike assertEquals(expected, actual) where the argument order is easy to mix up.

open as a page

What is Hamcrest, and how does the assertThat(actual, matcher) style of assertion differ from a classic assertEquals(expected, actual)?

level: juniorimportance: must knowfreq 70%
basics
~10 s

Hamcrest is a library of reusable 'matcher' objects. Instead of assertEquals(2, x), you write assertThat(x, is(2)). The matcher describes what you expect, reads almost like English, and prints a clear message when it fails.

open as a page

How do you assert on collections and iterables with AssertJ (contains, containsExactly, containsExactlyInAnyOrder, hasSize, extracting)?

level: middleimportance: must knowfreq 65%
basics
~20 s

Call assertThat on the collection, then chain: hasSize(n) for count, contains(a, b) to check elements are present, containsExactly(...) for the exact contents in order, containsExactlyInAnyOrder(...) ignoring order, and extracting("field") to assert on one property of each element.

open as a page

How do you assert that code throws an exception in AssertJ using assertThatThrownBy and assertThatExceptionOfType?

level: middleimportance: must knowfreq 60%
basics
~10 s

Wrap the failing call in a lambda: assertThatThrownBy(() -> service.run()).isInstanceOf(IllegalArgumentException.class).hasMessageContaining("bad"). It runs the lambda, catches the thrown exception, and lets you assert on its type and message. assertThatExceptionOfType(X.class).isThrownBy(() -> ...) is an equivalent style.

open as a page

Walk through the common Hamcrest core matchers (is, equalTo, not, nullValue, containsString, hasItem) — what does each check and how do you read them?

level: juniorimportance: should knowfreq 60%
basics
~10 s

equalTo checks equality, is wraps a matcher to read nicer, not inverts, nullValue checks for null, containsString checks a substring, and hasItem checks a collection contains an element. You combine them like assertThat(list, hasItem(equalTo(3))).

open as a page

What is JaCoCo, and how does it measure code coverage on the JVM?

level: juniorimportance: must knowfreq 70%
basics
~20 s

JaCoCo is a Java tool that measures how much of your code your tests actually run. While the tests execute, it watches the compiled code and records which lines and branches were hit, then produces a report.

open as a page

Explain JaCoCo's coverage metrics — instruction, line, branch, method, and complexity — and why line coverage alone can be misleading.

level: middleimportance: must knowfreq 65%
basics
~20 s

JaCoCo counts coverage in several ways: how many lines ran, how many of the true/false paths of if/switch ran (branches), how many low-level instructions and methods ran, and code complexity. Line coverage can hide untested branches — a line can run yet only one side of its condition is checked.

open as a page

How do you wire JaCoCo into a Gradle or Maven build to generate a coverage report?

level: middleimportance: should knowfreq 55%
basics
~20 s

Add the JaCoCo plugin to your build. It attaches an agent to the test run so coverage is recorded, then a report task turns that data into an HTML report. In Gradle you apply the jacoco plugin and run jacocoTestReport; in Maven you bind the prepare-agent and report goals.

open as a page

How do you enforce a minimum coverage threshold in the build so a drop fails CI, and how do you exclude code that shouldn't count?

level: seniorimportance: should knowfreq 50%
basics
~20 s

JaCoCo has a verification step that fails the build if coverage falls below a number you set. In Gradle it's jacocoTestCoverageVerification; in Maven it's the check goal with rules. You can also exclude generated or boilerplate code (DTOs, generated sources) so it doesn't drag the number down.

open as a page

What are the limits of code coverage as a quality signal, and how should an org set coverage policy without encouraging gaming?

level: principalimportance: nice to knowfreq 35%
basics
~20 s

Coverage shows which code ran during tests, not whether the tests check the right things. You can hit 100% with tests that assert nothing. So set realistic targets, focus on new/changed code, and pair coverage with techniques like mutation testing rather than chasing a single big percentage.

open as a page