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

JUnit+Mockito测试Spring微服务抛UnfinishedStubbingException异常解决

异常根因与修复方案

触发异常的核心原因

两个报错是并行关联的,分别对应接口定义缺陷、代码逻辑缺陷、测试用例写法缺陷三个层面:

  • HttpMediaTypeNotSupportedException: Content type '' not supported:Controller 中@GetMapping错误配置了consumes = MediaType.APPLICATION_JSON_VALUE。consumes用来限定接口可接收的请求媒体类型,这个判定是基于请求携带的Content-Type头实现的,而GET请求本身没有请求体,框架会直接匹配不到符合规则的处理器,抛出媒体类型不支持异常。
  • UnfinishedStubbingException:测试用例中的Mockito打桩流程被打断,本质是打桩语句没有形成完整闭环——打桩语句执行到参数匹配阶段时,中途插入了其他初始化逻辑,或是调试时触发了mock对象的toString()求值,导致Mockito判定上一次打桩没有完成。
  • 附带的代码逻辑bug:CarService.getByPlate方法中定义了局部变量car用来存返回值,最后却返回未定义的cars变量,存在编译报错风险。

分步修复操作

  • 修正Controller接口的配置错误

    注意:consumes属性的作用是筛选可匹配的请求,判定依据是请求头中的Content-Type值,和响应格式无关。GET请求没有请求体,本身不会携带Content-Type头,配置consumes属性后所有GET请求都会被判定为不支持的媒体类型。

    1. 删掉@GetMapping注解中consumes = {MediaType.APPLICATION_JSON_VALUE}的配置,仅保留produces = {MediaType.APPLICATION_JSON_VALUE}——GET接口不需要校验请求的媒体类型,只需要声明返回值格式即可。
    2. 调整接口参数的接收逻辑:当前接口用@RequestBody CarsRequest request作为入参,和GET请求的特性矛盾,GET请求没有请求体,无法通过@RequestBody接收参数。如果接口设计为从URL的query参数接收name/plate/price,需要把@RequestBody替换为@RequestParam;如果确实需要传递请求体,就把接口请求方式改成POST,从根源上消除逻辑矛盾。
  • 修正Service类的代码bug
    把getByPlate方法最后的返回值return cars;改成return car;,匹配方法内定义的局部变量,避免编译错误。
  • 修正测试用例的Mockito打桩逻辑
    调整打桩顺序,不要在打桩的参数匹配阶段插入其他对象初始化操作,保证每一处Mockito.when()语句紧跟对应的返回值配置,示例:
    // 提前完成所有测试数据的初始化
    Cars testCar = new Cars("BMW","TG35647", "15000","re",80000000, null,null);
    List<Cars> mockReturnList = new ArrayList<>();
    mockReturnList.add(testCar);
    
    // 打桩流程完整不打断,匹配任意入参格式即可
    Mockito.when(carService.getByPlate(
        Mockito.anyString(),
        Mockito.anyString(),
        Mockito.anyString()
    )).thenReturn(mockReturnList);
    

    调试时需要注意:如果在打桩还没形成完整闭环时,触发了mock对象的toString()方法(比如在IDEA调试器里展开mock对象的属性),也会打断Mockito的打桩流程,触发UnfinishedStubbingException。要等所有打桩逻辑全部写完、执行完后,再调试查看对象属性。

  • 修正JSON断言的格式错误
    当前测试用例中的预期JSON串格式不合法:用=代替键值对的冒号分隔、null值错误加了引号,JSONAssert解析时会直接匹配失败。调整为标准JSON格式即可,示例:
    String expected = "{\"name\":\"BMW\", \"plate\":\"TG35647\", " +
        "\"price\":\"15000\",\"brand\":\"re\", \"kilometers\":80000000, " +
        "\"revisiondate\":null, \"owner\":null}";
    

验证检查要点

  • 触发MockMvc请求时,GET请求不需要手动设置Content-Type头,只要Accept头匹配接口的produces规则,就不会出现媒体类型不支持的异常。
  • 所有Mockito打桩语句必须形成完整闭环,禁止在when(...)的参数匹配括号中间插入其他逻辑代码,避免触发打桩未完成异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 07:06:04