Summary of "Spring Boot testing: Zero to Hero by Daniel Garnier-Moiroux"
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
@SpringBootTestwithSpringExtensionis the core: it starts a Spring context for tests.- Web environment options:
WebEnvironment.MOCK(default): no real server, works withMockMvc— 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).
@LocalServerPortinjects the chosen port forRANDOM_PORTtests.
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/WebTestClientcan be wired against a real server port in integration tests.MockMvc+ aMockMvcRequestFactorycan makeRestTemplatecalls 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
@MockBeancombinations) — each distinct context slows the suite. - Prefer reusing the same context and use explicit cleanup (e.g.,
repository.deleteAll()in@BeforeEach) rather than@DirtiesContextwhen 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
@DynamicPropertySourceto 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
@AutoConfigureTestDatabaseor@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 likeatMost/pollInterval/untilAssertedto wait for async conditions.
7. Mockito tips
- Use
thenReturnsequences for ordered return values. - Use
Answerto compute return values from invocation arguments (for dynamic behavior). ReturnsDeepStubssupports 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
@ConfigurationPropertiesvalidation:- Validate with
javax/hibernate-validatorviaValidator.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).
- Validate with
9. Spring Security testing
@WithMockUserto simulate authenticated users inMockMvctests.- 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
MockMvctests for controllers and unit-like scenarios; add a few full-stackRANDOM_PORTtests 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
WebClientfor 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
@SpringBootTestand an empty test (starting point). MockMvccontroller tests: POST add todo; GET index; usingMockMvcRequestBuildersand matchers.- HtmlUnit
WebClienttest: select inputs, type values, click add button, assert content and JS-driven toggles. - Mock web (
MockMvc) vsRANDOM_PORT(real Tomcat) with@LocalServerPortand browser debugging. RestTemplateconfigured withMockMvcRequestFactoryto call mock stack.MockMvcTesterusage (AssertJ-style).OutputCaptureExtension+ custom AssertJ log assertion class for structured log assertions.@WebMvcTestexample: mocking service dependencies via@MockBeanor 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
@DynamicPropertySourceand 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:
thenReturnsequences,thenAnswer, deep stubs for fluent APIs. @ConfigurationPropertiesvalidation tests usingValidator, YAML mapping, andSpringApplicationBuilder.runfor 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.
Category
Technology
Share this summary
Is the summary off?
If you think the summary is inaccurate, you can reprocess it with the latest model.
Preparing reprocess...