Autowiring your controllers automagically when using MockMVC and Spring Cloud Contract

Featured image for sharing metadata for article

If you're building Spring (Boot) web APIs, you may be using Spring Cloud Contract for Consumer Driven Contract testing, to ensure that you're not pushing out breaking changes to your APIs.

In the case you're using MockMVC as your HTTP client layer, you may have a base test class defined similar to the documentation:

// via https://docs.spring.io/spring-cloud-contract/docs/3.1.0/reference/html/getting-started.html#getting-started-first-application-producer
package com.example.contractTest;

import org.junit.Before;

import io.restassured.module.mockmvc.RestAssuredMockMvc;

public class BaseTestClass {

    @Before
    public void setup() {
        RestAssuredMockMvc.standaloneSetup(new FraudController());
    }
}

However, you'll note that this requires you adding each controller manually.

You may amend it so you can make each controller @Autowired when running under @SpringBootTest, so you don't have to construct them all, but it still doesn't really scale nicely in the case you've got quite a few controllers, or that you're adding on extra work each time you want to introduce a new controller.

To make this easier, we can take one of two approaches to automagically wire in all our controllers:

Using the WebApplicationContext

The easiest way of doing this is to hook in an autowired WebApplicationContext which will have all the context required for the MockMVC setup:

import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.web.context.WebApplicationContext;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@DirtiesContext
public class BaseTestClass {

  @Autowired WebApplicationContext context;

  @BeforeEach
  void setup() {
    RestAssuredMockMvc.webAppContextSetup(context);
  }
}

Manually configuring beans

Alternatively, we can manually find all the beans that are required and hook them in:

import io.restassured.module.mockmvc.RestAssuredMockMvc;
import java.lang.annotation.Annotation;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.web.bind.annotation.RestController;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@DirtiesContext
public class BaseTestClass {

  @Autowired private ApplicationContext context;

  @BeforeEach
  void setup() {
    RestAssuredMockMvc.standaloneSetup(getBeansOfType(RestController.class, context));
    RestAssuredMockMvc.standaloneSetup(getBeansOfType(Controller.class, context));
  }

  private static Object[] getBeansOfType(
      Class<? extends Annotation> annotationType, ApplicationContext context) {
    var beans = context.getBeansWithAnnotation(annotationType);
    var list = beans.values().stream().toList();
    return list.toArray();
  }
}

Written by Jamie Tanna's profile image Jamie Tanna on , and last updated on .

Content for this article is shared under the terms of the Creative Commons Attribution Non Commercial Share Alike 4.0 International, and code is shared under the Apache License 2.0.

#blogumentation #spring #spring-boot #spring-cloud-contract.

This post was filed under articles.

Interactions with this post

Interactions with this post

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can use Comment Parade.