You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何Mock子服务REST请求并使用MockMvc测试@RestController?

解决MockMvc测试REST控制器+Mock子服务请求的方案

看起来你已经搭好了MockMvc测试的基础架子,接下来咱们把这两个需求落地得更完善:

一、优化MockMvc测试@RestController

你的初始代码已经能跑,但可以用Spring提供的自动配置简化流程,同时增加更全面的断言:

优化后的测试代码

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc // 自动配置MockMvc,无需手动通过WebApplicationContext构建
public class WebControllerIT {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void getStatusReturnsValidResponse() throws Exception {
        mockMvc.perform(get("/status")
                        .contentType(MediaType.APPLICATION_JSON)) // 指定请求类型,贴近真实调用场景
                .andExpect(status().isOk()) // 断言响应状态码
                .andExpect(content().contentType(MediaType.TEXT_PLAIN)) // 断言响应内容类型
                .andExpect(content().string(containsString("OK"))); // 断言响应体包含预期内容
    }
}

关键优化点

  • @AutoConfigureMockMvc 替代手动setup:Spring会自动注入配置好的MockMvc实例,省去手动构建的代码
  • 增加多维度断言:除了状态码,还可以验证响应内容类型、响应体内容,让测试更严谨

二、Mock子服务的REST请求

根据你调用子服务的方式,有两种常用方案:

方案1:用Spring自带的MockRestServiceServer(适合RestTemplate场景)

如果你的控制器是通过RestTemplate调用子服务,用MockRestServiceServer可以直接拦截RestTemplate的请求,无需启动额外服务:

假设你的业务代码是这样的:

@RestController
public class WebController {

    private final RestTemplate restTemplate;

    // 构造注入RestTemplate
    public WebController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @GetMapping("/status")
    public String getStatus() {
        // 调用子服务的健康检查接口
        String subServiceHealth = restTemplate.getForObject("http://sub-service/api/health", String.class);
        return "Main Service OK | Sub Service: " + subServiceHealth;
    }
}

对应的测试代码:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class WebControllerIT {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private RestTemplate restTemplate;

    private MockRestServiceServer mockServer;

    @Before
    public void setup() {
        // 将Mock服务绑定到RestTemplate,拦截所有请求
        mockServer = MockRestServiceServer.createServer(restTemplate);
    }

    @Test
    public void getStatusReturnsOkWithMockedSubService() throws Exception {
        // 配置Mock规则:当请求子服务的/api/health时,返回"UP"
        mockServer.expect(requestTo("http://sub-service/api/health"))
                .andExpect(method(HttpMethod.GET)) // 验证请求方法
                .andRespond(withSuccess("UP", MediaType.TEXT_PLAIN));

        // 执行MockMvc请求
        mockMvc.perform(get("/status")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(containsString("Main Service OK | Sub Service: UP")));

        // 验证Mock的请求是否被正确触发
        mockServer.verify();
    }
}

方案2:用WireMock(适合复杂HTTP场景)

如果需要模拟更复杂的子服务行为(比如POST请求、参数校验、错误状态码、响应延迟),WireMock是更灵活的选择,它是一个独立的HTTP Mock服务器:

第一步:添加依赖(Maven)

<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock-jre8</artifactId>
    <version>2.35.0</version>
    <scope>test</scope>
</dependency>

第二步:编写测试代码

@RunWith(SpringRunner.class)
// 让RestTemplate指向WireMock的地址
@SpringBootTest(properties = {"sub-service.url=http://localhost:8089"})
public class WebControllerIT {

    @Autowired
    private MockMvc mockMvc;

    private WireMockServer wireMockServer;

    @Before
    public void setup() {
        // 启动WireMock服务器,监听8089端口
        wireMockServer = new WireMockServer(8089);
        wireMockServer.start();
        WireMock.configureFor("localhost", 8089);
    }

    @After
    public void teardown() {
        // 测试结束后停止服务器
        wireMockServer.stop();
    }

    @Test
    public void getStatusHandlesSubServiceUnavailable() throws Exception {
        // 配置WireMock:模拟子服务返回500错误
        stubFor(get(urlEqualTo("/api/health"))
                .willReturn(aResponse()
                        .withStatus(500)
                        .withBody("ERROR")));

        mockMvc.perform(get("/status")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(containsString("Main Service OK | Sub Service: ERROR")));

        // 验证请求是否被正确调用
        verify(getRequestedFor(urlEqualTo("/api/health")));
    }
}

方案选择建议

  • 简单MockRestTemplate请求:用MockRestServiceServer足够,轻量且贴合Spring生态
  • 复杂HTTP场景模拟:用WireMock,支持更丰富的请求/响应配置,适合模拟真实子服务的各种行为

内容的提问来源于stack exchange,提问作者sschmeck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:02:07