使用mockMVC对controller层进行接口调试


背景

后端新增了一个对算法badCase排查功能,通过用户传入的内容按照节点成功或者失败走不同分支流程处理,流程结构如图所示。 判定流程的底层功能通过service层以RPC接口形式提供服务,结构定义如下:

java 复制代码
 public ResponseDTO badCaseDetect(RequestDTO userInputParam);

输入参数为RequestDTO类型的userInputParam包括传入的数据集和指标信息以及用户query,输出FinalResult为各个步骤节点的判定结果。为了避免大量if-else,可以采用工厂策略或者状态模式优化结构,解除耦合,而且中途注入其他service出现了null的问题有对应记录,后续完善这部分优化内容。

service层功能完成以后,接下来就是构建controller层并进行调试。


一、controller层构建

RequestMapping我们自己来定义,可以支持get或者post方式请求,两者都是可以带请求体的。这里我们用post请求:

java 复制代码
@Api(tags = "召回case排查接口")
@ResponseBody
@Controller
@RequestMapping("/recalling")
public class GroundingController{
    private static final Logger LOGGER = LoggerFactory.getLogger(GroundingController.class);
    @Resource
    GroundingService groundingService;
    @ApiOperation("recalling case 排查")
    @ResponseBody
    @RequestMapping(value = "/detect", method = RequestMethod.POST)
    public GroundingCaseDetectResponseDTO groundingCaseDetect(@ApiParam("query") @RequestParam(value = "query") String query,
                                                              @ApiParam("Id") @RequestParam(value = "id") String datasetId,
                                                              @ApiParam("dimIds") @RequestParam(value = "dimIds") List<String> dimIds) throws Exception {
        GroundingDTO groundingDTO = new GroundingDTO();
        groundingDTO.setQuery(query);
        groundingDTO.setId(Id);
      	groundingDTO.setDimIds(dimIds);
        LOGGER.error("请求内容:{}",groundingDTO);
        ResponseDTO finalResult = groundingService.badCaseDetect(groundingDTO);
        LOGGER.error("最终结果:{}",finalResult);
        return responseDTO;
    }
}

二、controller层测试

测试方法包括很多种,但是不同的方式对问题排查的便捷性不同。

1.本地集成测试方式-----本地先启动工程,然后直接用postman发请求,获取响应信息,这种方式一般信息较少,如果出了问题可能会很难排查。

2.本地单元测试方式-----通过Spring Test集成的mockMVC来进行测试,支持通过mock或者直接引入真实的service进行测试,完美集成Spring框架,便于本地断点调试发现定位问题。

3.合并发布后测试---,先合并到boe环境分支,构建发布到线下测试环境,然后通过postman构建请求发送,如果产生问题,可以通过全局logId访问日志平台,分析调用链路,排查问题,方便更直观更快速找到原因,但是合并代码冲突修正需要和其他同事沟通好。

代码层面先写个单测模块,过程中引入了mockMVC,为了求快直接用GPT生成的demo了,最初代码不一定是正确的

java 复制代码
public class GroundingControllerTest extends BaseTest{

    private static final Logger LOGGER = LoggerFactory.getLogger(GroundingControllerTest.class);
    @InjectMocks  
    private GroundingController controller;
  
    @Mock  
    private GroundingService groundingService;
  
    private MockMvc mockMvc;  
  
    public GroundingControllerTest() {
        initMocks(this);  
        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();  
    }  
  
    @Test  
    public void testGroundingCaseDetect() throws Exception {  
        String query = "*****************";
        String Id = "*********";
        List<String> dimIds = Arrays.asList("**********","*************");
        // 设置其他参数的值
        String cookie = "**********************";
        // 通过MockMvc发送请求,并传递查询参数
        MockHttpServletResponse response = mockMvc.perform(MockMvcRequestBuilders.post("/grounding/detect")
                        .contentType(MediaType.APPLICATION_JSON)
                        //.header("Cookie", cookie)
                        .param("query", query)
                        .param("Id", Id)
                       
                        .param("dimIds", String.join(",", dimIds))
                // 验证响应状态为200(或其他预期的HTTP状态码)
                .andExpect(status().isOk())
                // 返回响应结果进行进一步验证和处理
                .andReturn().getResponse();
        // 根据你的需求进行验证和断言
        LOGGER.error("测试结果:{}",response.getContentAsString());
    }  
}

1.先尝试本地postman测试

本地先启动工程,然后直接用postman发请求,获取响应信息,这种方式一般信息较少,出了问题很难排查。最初测试结果如下:

报错203状态码,想到自己没有传用户cookie,于是从线下环境发布的平台地址F12刷新随便获取了一个用户cookie补充到请求里面。

然后继续请求,发现报错501状态码---"第三方服务请求失败",这就有点看不懂了,于是转去进行mockMVC的单元测试。

2.使用mockMVC进行调试

之前的代码整体上结构看着问题不大,但是具体内容不一定正确,所以先运行一下这部分的test试下,发现最终结果是null,说明接口可能没有调用到。 于是我们可以以debug模式运行,发现问题出在 FinalResult finalResult = groundingService.badCaseDetect(groundingDTO); 运行到这一处时候,步入不了groundingService.badCaseDetect函数,直接跳过了,猜想可能是mock这个功能模拟了接口方法,并没有真实调用提供的接口方法(你猜它为什么叫mockMVC? 肯定是有mock功能的嘛),所以还是老老实实去官网查看对应的demo,把@Mock注解部分用真实的接口服务替换掉。

官网地址: chat.openai.com/c/150bc078-...

github上的demo: github.com/spring-proj... 并且可参考博客www.cnblogs.com/cxygg/p/174... (应该学会看官方的Api的demo,不是在别人的博客上面去抄)

对应修改之后的代码如下:

java 复制代码
@AutoConfigureMockMvc
public class GroundingControllerTest extends BaseTest{

    private static final Logger LOGGER = LoggerFactory.getLogger(GroundingControllerTest.class);

    @Autowired
    private GroundingController controller;

    @Autowired
    WebApplicationContext context;

    //在before里面初始化
    private MockMvc mockMvc;

    @Before
    public void before() {
        //初始化mockMvc
        //可以测试单个controller
        //mockMvc = MockMvcBuilders.standaloneSetup(mockMvcController).build();

        //可以测试所有controller
        mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }
 //..............后面都不用动
    }  
}

修改完成以后继续运行,发现程序跑通了,输出了预期的结果。

然后我们就可以愉快的合并代码发布到boe测试环境了,中途注意一点,合并代码时候,commit成功了,先本地测试一下,能正常跑通再push上去,不然提交了运行不了的代码,污染环境,就很烦。


总结

对于controller层的测试,后续推荐直接用Spring Test3.2版本之后提供的mockMVC功能,它支持单模块测试,也支持端到端测试;支持mock,也支持直接调用原始service接口,出了问题也方便我们本地debug断点调试定位问题,和Junit一样无缝集成Spirng框架,所以直接用mockMVC会方便很多。

相关推荐
微风粼粼1 分钟前
程序员在线接单
java·jvm·后端·python·eclipse·tomcat·dubbo
rebel35 分钟前
若依框架整合 CXF 实现 WebService 改造流程(后端)
java·后端
极客悟道1 小时前
颠覆传统虚拟化:在Docker容器中运行Windows系统的开源黑科技
前端·后端
调试人生的显微镜1 小时前
WebView 中 Cookie 丢失怎么办?跨域状态不同步的调试与修复经验
后端
weixin_437398211 小时前
转Go学习笔记(2)进阶
服务器·笔记·后端·学习·架构·golang
极客悟道2 小时前
巧解 Docker 镜像拉取难题:无需梯子和服务器,拉取数量无限制
后端·github
aiopencode2 小时前
iOS 出海 App 安全加固指南:无源码环境下的 IPA 加固与防破解方法
后端
liangdabiao2 小时前
AI一人公司?先搞定聚合支付!一天搞定全能的聚合支付系统
后端
AillemaC2 小时前
三分钟看懂回调函数
后端
yeyong2 小时前
越学越糟心,今天遇到又一种新的服务控制方式 snap,用它来跑snmpd
后端