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

使用Spock测试Spring 3控制器GET请求时出现错误求助

排查Spock测试Spring 3 GET控制器方法失败的问题

看起来你遇到的情况有点棘手——同一控制器里POST测试都正常,偏偏GET请求的测试出问题。先把你提到的关键代码整理出来,方便分析:

控制器代码

@RequestMapping(value = "/{accountHolderId}/xyz", method = RequestMethod.GET)
public @ResponseBody BaseResponse getHistoryByHolderId(HttpServletRequest request, @PathVariable String accountHolderId) {
    // 你的业务逻辑
}

Spock测试片段(补全常见写法)

def "GetHistoryByHolderId"() {
    given:
    def accountHolderId = "test-holder-id"
    // 其他测试准备工作

    when:
    def result = mockMvc.perform(get("/${accountHolderId}/xyz"))
            .andExpect(status().isOk())
            .andReturn()

    then:
    // 响应断言逻辑
    def response = new ObjectMapper().readValue(result.response.contentAsString, BaseResponse)
    response.success == true
}

下面是几个大概率能解决问题的排查方向,你可以逐一试试:


1. 路径变量的传递与绑定问题

Spring 3对@PathVariable的绑定有个小坑:如果编译时没有保留参数名(比如开启了编译优化),框架可能无法自动匹配路径占位符和方法参数。哪怕你参数名和占位符都是accountHolderId,也可能出问题。试试显式指定参数名:

public @ResponseBody BaseResponse getHistoryByHolderId(HttpServletRequest request, @PathVariable("accountHolderId") String accountHolderId)

另外,检查测试里的路径拼接是否正确——比如控制器类上有没有额外的@RequestMapping前缀(比如/api),如果有的话,测试请求路径要写成/api/${accountHolderId}/xyz,别漏掉前缀。

2. HttpServletRequest的模拟问题

你的控制器方法依赖HttpServletRequest,如果测试里没正确模拟这个对象,很容易报错。比如控制器里用到了request.getHeader()、request.getParameter()这类方法,就得在测试里把这些调用mock出来:

given:
def mockRequest = Mock(HttpServletRequest)
// 模拟你需要的请求方法
mockRequest.getHeader("Authorization") >> "Bearer test-token"

when:
def result = mockMvc.perform(get("/${accountHolderId}/xyz")
        .requestAttr("javax.servlet.http.HttpServletRequest", mockRequest)) // 把mock对象注入请求
        .andExpect(status().isOk())
        .andReturn()

如果是用Spring上下文加载测试,也要确保request对象能被正确注入到测试环境中。

3. 请求方法与路径的匹配校验

虽然你控制器指定了method=GET,但还是要确认测试里发送的确实是GET请求——别不小心写成了post()或者其他方法。另外,可以开启Spring MVC的日志调试,看看实际请求的路径和方法是否和控制器的映射匹配,日志里会打印出请求匹配的过程,很容易定位问题。

4. 响应序列化/反序列化问题

如果测试是在断言响应体,先打印出result.response.contentAsString看看实际返回的内容是什么。有可能是BaseResponse缺少无参构造器、或者某些字段的序列化规则有问题,导致Jackson(Spring 3默认用的序列化工具)无法正确解析响应。

5. Spock与Spring 3的版本兼容性

Spring 3是比较老的版本了,如果你用的是Spock 2.x及以上版本,可能会有兼容性问题。建议检查依赖版本,换成Spock 1.x系列(比如1.3-groovy-2.5),这个版本和Spring 3的适配性更好。


最后给你一个完整的示例测试代码,覆盖了上面提到的关键点:

import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.setup.MockMvcBuilders
import spock.lang.Specification

class YourControllerSpec extends Specification {
    MockMvc mockMvc
    YourController controller = new YourController()
    ObjectMapper objectMapper = new ObjectMapper()

    def setup() {
        // 初始化MockMvc
        mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
    }

    def "GetHistoryByHolderId should return successful response"() {
        given:
        def accountHolderId = "12345"
        def mockRequest = Mock(HttpServletRequest)
        // 模拟控制器需要的request方法
        mockRequest.getHeader("X-Request-Id") >> "test-123"

        when:
        def result = mockMvc.perform(get("/${accountHolderId}/xyz")
                .requestAttr("javax.servlet.http.HttpServletRequest", mockRequest))
                .andExpect(status().isOk())
                .andReturn()

        then:
        def actualResponse = objectMapper.readValue(result.response.contentAsString, BaseResponse)
        actualResponse.success == true
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:36:26