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

Mockito.when()设置桩时触发已有Mock逻辑抛出NPE问题

问题说明

这是Mockito使用中的常见问题,测试配置存在逻辑缺陷。
触发NPE的核心原因:

  • Mockito.when(mock.method(matcher))语法在设置新桩时,会真实执行一次mock.method(matcher)调用,用于捕获方法签名和匹配规则。
  • 你在@BeforeEach阶段已经通过Mockito.any()匹配器为addAddress方法注册了全局桩,any()会匹配所有入参,包括设置新桩时传入的匹配器代理对象。
  • 执行测试方法内的桩设置代码时,全局桩的thenAnswer逻辑被触发,此时传入的参数是Mockito内部的匹配器代理,不是真实构造的Address对象,调用getValues()返回null,最终触发空指针。
解决方案

你可以选择以下任意一种方案修复,推荐组合使用方案1和方案4:

  • 方案1:给全局桩的Answer逻辑增加空值判断,避免直接调用null对象的方法
    private void mockAddressClient() {
      Mockito
        .when(addressClient.addAddress(Mockito.any()))
        .thenAnswer(
          in -> {
            de.vbg.suvi.api.address.v1.model.Address adr = in.getArgument(0);
            de.vbg.suvi.api.address.v1.model.ValueAddress values = adr.getValues();
            // 新增空值判断
            if (values == null) {
              return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
            }
            AddressResponse addressResponse =
              new AddressResponse()
                .id(UUID.randomUUID())
                .streetLine1(values.getStreetLine1())
                .streetLine2(values.getStreetLine2())
                .streetNumber(values.getStreetNumber())
                .zipCode(values.getZipCode())
                .city(values.getCity())
                .country(values.getCountry());
            addresses.put(addressResponse.getId(), addressResponse);
            return new ResponseEntity<>(addressResponse, HttpStatus.CREATED);
        });
    }
    
  • 方案2:将测试方法内的桩设置语法从when().thenThrow()替换为doThrow().when(),do系列语法不会在设置桩时触发已有桩的逻辑
    // 替换原测试方法内的桩设置代码
    Mockito.doThrow(
        new ValidationException(
          List.of(
            new SuviFieldValidationError(
              ViolationCode.INVALID, "message", "streetNumber"))))
      .when(addressClient)
      .addAddress(Mockito.argThat(a -> a.getPlaceId().equals(placeId)));
    
  • 方案3:给@BeforeEach内的全局桩添加lenient()宽松模式修饰,避免桩设置阶段的调用触发旧桩逻辑
    // 修改全局桩写法
    Mockito.lenient().when(addressClient.addAddress(Mockito.any()))
      // 后续thenAnswer逻辑不变
    
  • 方案4:移除@BeforeEach内的全局通用桩,每个测试方法按需设置自己需要的桩规则,从根源上避免桩冲突。

注意:Mockito桩匹配遵循「后注册的桩优先匹配」规则,如果你保留全局桩,测试方法内注册的特殊桩在实际执行业务逻辑时会优先生效,不会被全局桩覆盖,不需要担心逻辑冲突。

内容的提问来源于stack exchange,提问作者Moritz Schmitz v. Hülst

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 03:18:16