Java Mockito单元测试中服务调用返回null问题排查
问题结论
该问题完全是测试侧Mock配置及代码写法错误导致,和生产环境client服务的逻辑无关。其他开发人员正常调用是因为走的是真实client逻辑,没有走Mock桩逻辑。
具体根因排查
- Mock实例不匹配:
你在测试代码里手动mock了client实例,给它打了doReturn(res)的返回桩,但你没有把这个mock出来的client、或者你mock的clientFactory注入到被测类classAToTest中。被测类内部持有的client实例根本不是你打桩的这个对象,你配置的返回规则自然不会生效。
另外你测试代码里打桩用的变量名是client,最后verify调用的却是creativeToolsClient,明显存在变量名混淆的问题,进一步说明你操作的mock对象和被测类实际持有的对象不是同一个。 - @Mock注解未生效:
你用@Mock注解标记了响应对象res,但从你贴的setUp代码看,你没有初始化Mockito注解:既没有加Mockito对应的Runner,也没有调用MockitoAnnotations.openMocks(this),这会导致res本身就是null,就算打桩生效,返回值也会是null。 - 参数匹配不一致:
你打桩时匹配的入参类型是ServiceProto.PutItemsRequest,但verify时用的入参类型是IngestionServiceProto.PutItemsRequest,如果这两个不是同一个类,参数匹配会直接失败,Mock不会触发你配置的返回规则。 - 异常被吞干扰排查:
你写了空的catch块捕获NullPointerException,异常发生时没有任何输出,根本看不到具体栈信息,会直接拖慢问题定位效率。 - 业务代码存在语法问题:你贴的被测方法代码里,
client.putItems(...)后多写了一个.build()调用,如果putItems本身返回的就是PutItemsResponse类型,多余的build调用要么编译失败,要么在putItems返回mock对象时触发空指针。
修复步骤
- 初始化Mockito注解。在测试类上添加
@RunWith(MockitoJUnitRunner.class),或者在setUp方法第一行加MockitoAnnotations.openMocks(this),保证@Mock标记的res对象被正常初始化,不是null。 - 统一Mock实例,保证依赖注入正确。如果你是通过构造方法向ClassAToTest传依赖,new被测类实例时必须把你mock的client、clientFactory作为参数传入,不要让被测类内部自己初始化client;如果是注解注入依赖,用@InjectMocks注解标记被测类实例,自动注入mock对象。同时统一变量名,打桩和verify时操作同一个mock client对象,不要出现变量名混用的问题。
- 统一参数匹配规则。确认putItems方法的入参类全限定名,打桩和verify时用相同的Request类型做匹配,避免因类型不匹配导致桩逻辑不触发。
- 删掉空的catch块。测试阶段不要吞异常,方便出错时通过栈信息快速定位问题。
- 检查被测方法代码,删掉putItems返回值后多余的
.build()调用,保证业务代码逻辑正确。
内容的提问来源于stack exchange,提问作者Manny
相关产品推荐
相关产品推荐

