Testing Concepts

JUnit 5, Mockito, and Spring testing — core concepts explained in depth.

Sort
1
Java

Test Data Lifecycle and What to Test at the Database Layer

Why cleaning up test data at the start beats the end, why in-memory databases still don't belong in integration tests despite Testcontainers changing the container-overhead trade-off, and why reads and repositories deserve a lower testing bar than writes.

2
Java🔬 Lab

Database Testing Prerequisites and Transaction Management

Why schema and reference data belong in source control, why migration-based delivery beats state-based once real data exists (the data-motion argument), and why integration tests need a separate transaction per arrange/act/assert section instead of reusing one session.

3
Java🔬 Lab

Reusing Test Fixtures, Parameterized Tests, and Assertion Libraries

Why constructor/@BeforeEach-based fixture reuse couples tests to each other and hurts readability, why private factory methods (Object Mother) are the better default, when to reach for @ParameterizedTest and @MethodSource, and how AssertJ's fluent style avoids the expected/actual argument-order trap.

4
Java

Structuring and Naming Unit Tests: AAA and Plain-English Names

The AAA pattern's real rules beyond "use three sections": never write multiple act sections or an if statement in a test, treat a multi-line act section as a production-code smell not a test problem, and reject rigid MethodUnderTest_Scenario_Result naming for plain-English test names.

5
Java

Mocking Best Practices: Integration Tests Only, Spies, and Types You Own

Concrete, sometimes counter-intuitive rules for using mocks well beyond the mock-vs-stub distinction: mocks belong only in integration tests, never unit tests on pure domain logic; hand-written spies often beat a generic mock's verify(); assertions must check call count, not just occurrence; and you should only ever mock types your own codebase defines.

6
Java🔬 Lab

Unit Testing Anti-Patterns: Private Methods, Leaked Domain Knowledge, and Time

Why testing private methods, exposing private state, reimplementing the SUT's logic in a test, polluting production code with test-only switches, mocking concrete classes, and calling the system clock directly all trace back to the same root cause — from Khorikov, Chapter 11 "Unit testing anti-patterns".

7
Java

Functional Architecture: Separating Decisions from Side Effects for Testability

Learn the functional-core/imperative-shell pattern for pulling business decisions out of side-effect-laden code so the decision logic becomes trivially output-based testable with zero mocks, and understand the real costs — a shell that still needs integration tests, allocation overhead from immutability in hot paths, and domain logic that can't always be cleanly separated this way.

8
Java

Output-Based, State-Based, and Communication-Based Testing

The three ways a unit test can verify behavior — checking a returned output, checking resulting state, or checking a call made to a collaborator — and why output-based testing produces the highest-quality tests but only works for side-effect-free code, leaving state-based testing as the reasonable default and communication-based testing (mocks) as the rare exception.

9
Java🔬 Lab

Observable Behavior vs. Implementation Details: Why Mocks Make Tests Fragile

A mock (outgoing command) and a stub (incoming query) answer different questions, and asserting interactions with a stub is a classic overspecification mistake. The deeper principle: mocking itself doesn't cause fragile tests — mocking an interaction that's an implementation detail (intra-system, no client goal behind it) rather than observable behavior (a call that crosses the application boundary and stays visible outside it) does. The fix isn't avoiding mocks, it's mocking only at true system boundaries.

10
Java

Managed vs. Unmanaged Dependencies in Integration Tests

Why an integration test should hit a real database (a managed dependency) but mock an SMTP server or message bus (an unmanaged dependency) — and why mocking a managed dependency quietly breaks resistance to refactoring.

11
Java

Classical vs. London Schools of Unit Testing

Two genuinely different definitions of test "isolation" — mock every collaborator (London) vs. mock only shared/volatile dependencies (classical) — and why they disagree about what a unit even is.

12
Java

Testing by Code Type: The Four Quadrants

A map of production code by complexity/domain significance and collaborator count — where unit testing pays off best, where it's a waste, and how the Humble Object pattern fixes the code that's genuinely hard to test.

13
Java🔬 Lab

The Four Pillars of a Good Unit Test

Protection against regressions, resistance to refactoring, fast feedback, and maintainability — the four attributes that judge any automated test, and why no test can maximize all four at once.

14
Java

The Test Pyramid Strategy

How to distribute tests across levels — many fast unit tests at the base, fewer integration/system/acceptance tests toward the top — what to test at each level, and which tool fits each, from JUnit in Action, Third Edition, Ch. 22.

15
Java

BDD with Cucumber

Writing behavior specifications in business-readable Gherkin (Given/When/Then) and binding them to Java step definitions with Cucumber — with today's io.cucumber + JUnit 5 Platform setup replacing the book's obsolete info.cukes/@RunWith(Cucumber.class), from JUnit in Action, Third Edition, Ch. 21.

16
Java

Test-Driven Development

The red-green-refactor cycle — write a failing test first, add the smallest code to pass, then refactor safely — driving design with JUnit 5, from JUnit in Action, Third Edition, Ch. 20.

17
Spring🔬 Lab

Testing JPA and Hibernate

Testing a JPA/Hibernate persistence layer — entity mapping, persistence.xml, and EntityManager queries against a test database — with the critical javax→jakarta package move (Hibernate 6 / Spring 6), the @DataJpaTest slice, and Testcontainers for real-database integration tests, from JUnit in Action, Third Edition, Ch. 19.4–19.6.

18
Spring🔬 Lab

Testing JDBC and Spring JDBC

Testing data-access code against an in-memory database — from raw JDBC (Connection/PreparedStatement/ResultSet) to Spring's JdbcTemplate/NamedParameterJdbcTemplate — with notes on obsolete Class.forName driver loading, injected JdbcTemplate over JdbcDaoSupport, and the @JdbcTest slice, from JUnit in Action, Third Edition, Ch. 19.1–19.3.

19
Spring🔬 Lab

Testing a REST API with MockMvc

Driving a Spring REST controller through MockMvc — simulated HTTP requests, status/content-type/jsonPath assertions, and a mocked data layer — with today's @WebMvcTest slice, @MockitoBean (replacing @MockBean), and the Spring 6 NestedServletException change, from JUnit in Action, Third Edition, Ch. 18.

20
Spring🔬 Lab

Testing Spring Boot Applications

Bootstrapping a full application context with @SpringBootTest — component scanning, auto-configuration, and bean autowiring — plus today's faster test slices (@WebMvcTest, @DataJpaTest) and the @MockBean→@MockitoBean change, from JUnit in Action, Third Edition, Ch. 17.

21
Spring🔬 Lab

Testing Spring with SpringExtension

Loading a Spring ApplicationContext into a JUnit 5 test with @ExtendWith(SpringExtension.class) and @ContextConfiguration, injecting beans via @Autowired — with a note on today's @SpringJUnitConfig shortcut, from JUnit in Action, Third Edition, Ch. 16.

22
Java

Selenium Browser Testing

Driving a real browser through the WebDriver interface — element lookup, cross-browser parameterized tests, and the Page Object model — with notes on what changed from the book's Selenium 3 to today's Selenium 4, from JUnit in Action, Third Edition, Ch. 15.

23
Java

JUnit 5 Extension Model

The five extension points (conditional execution, lifecycle callbacks, parameter resolution, exception handling, instance postprocessing) behind @ExtendWith — the same mechanism MockitoExtension and SpringExtension use — from JUnit in Action, Third Edition, Ch. 14.

24
Java🔬 Lab

Test Doubles: Stubs and Mocking

Stubs vs. mocks as two strategies for faking a collaborator, and how to create and verify mocks with Mockito — from JUnit in Action, Third Edition, Ch. 7–8.

25
Java

Test Quality and Testable Code

Measuring coverage with JaCoCo, writing testable code (Law of Demeter, composition over conditionals), and how TDD/BDD/mutation testing fit the development cycle — from JUnit in Action, Third Edition, Ch. 6.

26
Java

Software Testing Principles

Unit vs. integration vs. system vs. acceptance testing, and black-box vs. white-box testing — the vocabulary behind how a test suite is organized, from JUnit in Action, Third Edition, Ch. 5.

27
Java

JUnit 5 Architecture

How Platform, Jupiter, and Vintage fit together to run new and legacy tests side by side, plus a short JUnit 4-to-5 migration reference — from JUnit in Action, Third Edition, Ch. 3.1/3.3 (and a short Ch. 4 note).

28
Java🔬 Lab

JUnit 5 Fundamentals

The JUnit 5 test lifecycle, assertions vs. assumptions, nested/tagged tests, and parameterized/dynamic tests — from JUnit in Action, Third Edition, Ch. 2.