Video summary

Spring Boot testing: Zero to Hero by Daniel Garnier-Moiroux

Main summary

Key takeaways

Technology

Spring Boot testing: Zero to Hero (Daniel Garnier‑Moiroux, Devoxx 2024)

Overview

  • Focus: practical Spring Boot testing tools, patterns and tradeoffs (not general testing theory).
  • Presenter: Daniel Garnier‑Moiroux (Broadcom, Spring team — works especially on Spring Security and enterprise Spring tooling).
  • Sponsor mentioned on stage: Kos.

Key concepts, tools and test types

1. Test types and web environments

  • @SpringBootTest with SpringExtension is the core: it starts a Spring context for tests.
  • Web environment options:
    • WebEnvironment.MOCK (default): no real server, works with MockMvc — fast and suitable for most cases.
    • WebEnvironment.RANDOM_PORT: starts a real servlet container (Tomcat/Jetty/etc.) on a random port — used for full-stack/integration tests (session persistence, custom logging valves, debugging via browser).
    • WebEnvironment.DEFINED_PORT: avoid if possible (port clashes).
  • @LocalServerPort injects the chosen port for RANDOM_PORT tests.

2. Request / HTML testing approaches

  • MockMvc: simulate HTTP requests against the Spring MVC stack (fast, default for server-less web tests).
  • HtmlUnit-based WebClient (org.htmlunit): lightweight Java headless browser that executes JavaScript. Useful for testing JS-driven interactions without Selenium/real browser.
    • Limitation: not a full Chrome/Firefox — won’t cover features like WebAuthn/passkeys.
  • RestTemplate / WebTestClient can be wired against a real server port in integration tests.
  • MockMvc + a MockMvcRequestFactory can make RestTemplate calls hit the mocked MVC stack.
  • Use Selenium / Playwright / Puppeteer / Cypress when you need full-browser testing or heavy JS testing — often better to test JS in the JS ecosystem.

3. MockMvcTester (newer API)

  • Provides an AssertJ-style fluent API on top of MockMvc (reduces static import clutter; supports fluent body/text assertions).

4. Test slices and context hygiene (performance & caching)

  • Slice tests (e.g., @WebMvcTest, @DataJpaTest) load only relevant parts of the app to speed tests and reduce required mocking.
    • @WebMvcTest: loads controllers, controller advice, converters, filters, security filter chain, etc., but not repositories/services unless explicitly imported or mocked.
    • @DataJpaTest: configures JPA/Hibernate + a test database for repository-level testing.
  • Use @MockBean (or the new name in Boot 3.4+) to supply mocks for dependencies in slice tests, or provide test configuration beans to satisfy slice needs.
  • Context caching:
    • Spring’s test context cache attempts to reuse contexts; differences in configuration/properties/profiles cause new contexts to be created.
    • Avoid creating many slightly different contexts (many active profiles or many different @MockBean combinations) — each distinct context slows the suite.
    • Prefer reusing the same context and use explicit cleanup (e.g., repository.deleteAll() in @BeforeEach) rather than @DirtiesContext when possible.
    • Default context cache size is limited (32 by default); exceeding it evicts cached contexts and forces rebuilds.

5. Testcontainers (real external services in tests)

  • Use Testcontainers to run realistic dependencies (Postgres, Redis, Kafka, Keycloak, etc.) in containers for tests instead of managing DBs manually.
  • Spring Boot Testcontainers integration: add container configuration and wire container beans; Spring can map container connection info into the app using service-connection support.
  • For non-supported containers use @DynamicPropertySource to register properties (host/port) from started containers.
  • Singleton/static container pattern: make containers static (start once) to avoid starting/tearing down containers repeatedly across contexts — tradeoff is shared state vs speed.
  • Use @AutoConfigureTestDatabase or @AutoConfigureTestDatabase(replace = NONE) as needed when disabling H2 replace behavior.

6. Assertion libraries and testing utilities

  • AssertJ recommended for fluent, readable assertions and strong failure messages. Hamcrest is available but less preferred by the presenter.
  • OutputCaptureExtension (Spring) captures stdout/stderr so tests can assert on logs. The presenter demonstrated building custom AssertJ assertions for log lines (parse with regex, build fluent assertions).
  • Use awaiting/polling utilities (Awaitility-like) for asynchronous polling/waiting — avoid Thread.sleep() in tests. Use constructs like atMost / pollInterval / untilAsserted to wait for async conditions.

7. Mockito tips

  • Use thenReturn sequences for ordered return values.
  • Use Answer to compute return values from invocation arguments (for dynamic behavior).
  • ReturnsDeepStubs supports mocking fluent APIs (e.g., restClient.get().uri(...).retrieve().bodyToMono()).
  • Prefer integration tests / Testcontainers over heavy mocking of external services when feasible.

8. Testing configuration properties

  • For @ConfigurationProperties validation:
    • Validate with javax/hibernate-validator via Validator.validate(...) for unit tests (fast).
    • Test YAML property mapping by mapping YAML into property objects (using YAML ObjectMapper) and then validate.
    • To assert failures at context startup, use SpringApplicationBuilder.run(...) (programmatic start).
    • Useful when configuration has complex business validation (mutually exclusive modes, required groups, uniqueness).

9. Spring Security testing

  • @WithMockUser to simulate authenticated users in MockMvc tests.
  • Security MockMvc request post-processors: add CSRF tokens, set authentication tokens, or set OIDC claims without a real browser; useful for testing CSRF-protected endpoints and OIDC/OAuth login flows.
  • OIDC login testing: use oidcLogin() post-processor and set token claims (email, etc.) to emulate external identity providers.

Practical tips, tradeoffs & recommendations

  • Start with fast slice and MockMvc tests for controllers and unit-like scenarios; add a few full-stack RANDOM_PORT tests for integration verification (session persistence, logging, DB serialization).
  • Avoid too many distinct test contexts (profiles/beans/properties) — reuse contexts and limit variations.
  • Use Testcontainers for DB-dependent behavior that needs production-like DB features (e.g., Postgres full‑text search).
  • Use HtmlUnit-based WebClient for light JavaScript tests; use JS ecosystem tools (Playwright / Cypress / Puppeteer) for heavier front-ends.
  • Build custom AssertJ assertions for repeated parsing/assertion patterns (e.g., logs).
  • Avoid Thread.sleep(); use await/poll utilities in tests.

Examples / demos shown

  • Basic @SpringBootTest and an empty test (starting point).
  • MockMvc controller tests: POST add todo; GET index; using MockMvcRequestBuilders and matchers.
  • HtmlUnit WebClient test: select inputs, type values, click add button, assert content and JS-driven toggles.
  • Mock web (MockMvc) vs RANDOM_PORT (real Tomcat) with @LocalServerPort and browser debugging.
  • RestTemplate configured with MockMvcRequestFactory to call mock stack.
  • MockMvcTester usage (AssertJ-style).
  • OutputCaptureExtension + custom AssertJ log assertion class for structured log assertions.
  • @WebMvcTest example: mocking service dependencies via @MockBean or providing test configuration/imports.
  • Custom slice test using manual @ImportAutoConfiguration (e.g., include Thymeleaf view config).
  • @DataJpaTest + Testcontainers Postgres with a specific Postgres schema (for full‑text search).
  • Testcontainers @DynamicPropertySource and service-connection mapping for Spring Boot.
  • Testcontainers static/singleton container pattern to reduce container churn.
  • Awaitility-like wait/poll sample for asynchronous testing.
  • Mockito examples: thenReturn sequences, thenAnswer, deep stubs for fluent APIs.
  • @ConfigurationProperties validation tests using Validator, YAML mapping, and SpringApplicationBuilder.run for startup-failure tests.
  • Spring Security testing: @WithMockUser, security request post-processors (csrf(), oidcLogin(...)) and verifying secured endpoints.

References / resources

  • start.spring.io — project generation / dependency management
  • Spring Boot reference docs (testing and slices)
  • Testcontainers — testcontainers.org
  • AssertJ documentation
  • Mockito documentation
  • HtmlUnit / WebClient
  • JS tooling for browser testing: Playwright / Puppeteer / Cypress

Main speaker / sources

  • Daniel Garnier‑Moiroux — Spring team (Broadcom), presenter.
  • Implicit tools and sources referenced: Spring Boot docs, Testcontainers, Mockito, AssertJ, HtmlUnit, MockMvc, and common JS E2E tools (Playwright/Cypress/Puppeteer).

Note: concrete example code snippets (MockMvc / WebClient / Testcontainers / AssertJ / Mockito samples) were demonstrated during the session and can be extracted as paste-ready examples if needed.

Rate this summary

Your feedback will help improve summaries.

Improve this summary

Reprocess with a stronger model when the summary feels incomplete or inaccurate.

Pro

Translate summary in another language

Pro

Ask questions to this video

Chat for follow-up questions, clarifications, and source-backed answers.

Coming soon

Share this summary

Original video