skip to content

How does the producer-side test generation work, and what is the base class for?

level: middleimportance: must knowfreq 50%

answer

  1. plugin generates test per contract
  2. extends YOUR base class
  3. RestAssuredMockMvc.standaloneSetup / webAppContextSetup
  4. baseClassForTests / packageWithBaseClasses / baseClassMappings
  5. testMode MOCKMVC/WEBTESTCLIENT/EXPLICIT

basics

~20 s

The Verifier build plugin reads each contract and generates a JUnit test that sends the contract's request to your controller and checks the response. You provide a base class that sets up the controller (MockMvc/RestAssured) so the generated test can run.

solid answer

~40 s

At build time the Spring Cloud Contract Verifier plugin scans src/test/resources/contracts and code-generates one JUnit test per contract into target/generated-test-sources. Each generated test fires the contract's request and asserts the response — this is what proves the real controller honors the contract. Generated tests don't know how to bootstrap your app, so they extend a base class you write. In the base class you configure the test entry point: either RestAssuredMockMvc.standaloneSetup(controller) / webAppContextSetup, or point RestAssured at a running port. You wire the base class via the plugin's baseClassForTests, or packageWithBaseClasses / baseClassMappings for per-package mapping. If a generated test fails, your implementation diverged from the contract. After tests pass, the same build packages the WireMock stubs JAR.

code

java · 21 lines
java
// Base class the generated tests extend.
// Wired via plugin config: <baseClassForTests>com.example.UserContractBase</baseClassForTests>
public abstract class UserContractBase {

    @BeforeEach
    void setup() {
        UserService service = Mockito.mock(UserService.class);
        Mockito.when(service.findById(42L))
               .thenReturn(new User(42L, "Ada"));

        // Standalone MockMvc: fast, in-process, no server port
        RestAssuredMockMvc.standaloneSetup(new UserController(service));
    }
}

// A generated test (do not edit) will look roughly like:
//   public class UserTest extends UserContractBase {
//     @Test void validate_shouldReturnUser() {
//        given()... when().get("/users/42").then().statusCode(200)...
//     }
//   }

go deeper

for a junior

Know that the plugin auto-generates producer tests and you supply a base class to set up the controller.

for a middle

Explain generation location, base-class responsibilities, and the three ways to wire it (baseClassForTests / packageWithBaseClasses / baseClassMappings).

for a senior

Discuss testMode trade-offs (MOCKMVC vs WEBTESTCLIENT vs EXPLICIT) and how base-class mocking keeps generated assertions deterministic.

for a principal

Reason about isolating controller slices vs full-context tests for contract fidelity, and pipeline placement so stub JARs only publish after verification passes.

## Build-time generation The **Spring Cloud Contract Verifier** plugin (`spring-cloud-contract-maven-plugin` or the Gradle `spring-cloud-contract` plugin) runs during the build. It reads every contract under `src/test/resources/contracts/**` and **code-generates** a JUnit (or Spock) test per contract into `target/generated-test-sources/contracts` (Maven) — these are then compiled and executed as part of the test phase. You do not write these tests; they are regenerated each build. ## What a generated test does For an HTTP contract, the generated test: 1. Builds the request from the contract (method, URL, headers, body). 2. Sends it — by default using **RestAssuredMockMvc** (in-process, no network) or plain RestAssured against a real port, depending on your setup. 3. Asserts the response status, headers, and body match the contract, applying any matchers. This is the crucial half of CDC: it verifies the **actual producer implementation** satisfies the contract, so the stubs consumers rely on are trustworthy. ## Why a base class The generated test class is abstract about environment — it doesn't know how to start your Spring context or which controller to hit. So each generated test **extends a base class you provide**. Typical responsibilities of the base class: - Set up the test mode. For MockMvc mode: `RestAssuredMockMvc.standaloneSetup(new MyController(mockedService))` for a fast standalone slice, or `RestAssuredMockMvc.webAppContextSetup(context)` / `@AutoConfigureMockMvc` with `@SpringBootTest` for a fuller context. - Stub/mock collaborators (services, repositories) so the controller returns the contracted data deterministically. - For explicit mode / real port: set `RestAssured.baseURI`/`port`. ## Wiring the base class You tell the plugin which base class to use via configuration: - `baseClassForTests` — a single base class for all contracts. - `packageWithBaseClasses` — convention: a contract in package `foo.bar` uses base class `...BarBase`. - `baseClassMappings` — regex-to-base-class mappings for finer control. ## Test modes The plugin's `testMode` can be `MOCKMVC` (default, in-process), `WEBTESTCLIENT` (reactive), `EXPLICIT` (real HTTP against a deployed/running app), or `JAXRSCLIENT`. ## Gotchas - **Missing/incorrect base class** is the most common failure — generated tests won't compile or NPE because the controller/mocks aren't set up. - Base class must make collaborators return exactly what the contract expects; otherwise the generated assertion fails. - Generated sources live under `target/`; don't edit them, edit the contract or base class. - Because tests are regenerated, a contract change immediately reshapes the test — no manual sync. ## When to use which mode Use MOCKMVC standalone for fast, isolated controller verification (most cases). Use `@SpringBootTest` webAppContextSetup when filters/security/converters matter. Use EXPLICIT when you must hit a really-deployed instance.

  • Where do generated tests live and should you commit them?
    They are generated into target/generated-test-sources/contracts (Maven) each build and compiled/run automatically. You don't commit or edit them — you edit the contract or the base class; the plugin regenerates them.
  • What's the difference between MOCKMVC and EXPLICIT test modes?
    MOCKMVC runs in-process via RestAssuredMockMvc (no real socket) — fast and isolated. EXPLICIT sends real HTTP over a port to a running app, useful for verifying a deployed instance or full network stack, but slower and needs the app up.

saying these in an interview costs you the question

  • Saying you hand-write the producer tests (they're generated).
  • Not knowing the base class exists or what it configures.
  • Thinking the generated tests are what consumers use (those are the stubs).

context