JUnit测试运行通过但Jacoco显示0%覆盖,如何处理Mapper内新建对象的测试问题
问题1:如何Mock方法内部new出来的对象并完成Setter注入
你当前代码里的StudentOldTestingReturn、OldBatchName都是在业务方法内部直接实例化的,默认Mockito无法直接Mock这类对象,两种解决方案:
方案1:使用Mockito 3.5+提供的mockConstruction特性(无需改造业务代码)
在测试方法里可以临时Mock指定类的所有构造方法调用,示例代码:
@Test void OldLogicTestingMockTest() throws Exception { // 先Mock OldBatchName的构造 try (MockedConstruction<OldBatchName> mockedBatch = Mockito.mockConstruction(OldBatchName.class, (mock, context) -> { // 模拟setter赋值后的返回值 Mockito.when(mock.getId()).thenReturn("mockId"); Mockito.when(mock.getName()).thenReturn("mockName"); })) { // 再Mock StudentOldTestingReturn的构造 try (MockedConstruction<StudentOldTestingReturn> mockedReturn = Mockito.mockConstruction(StudentOldTestingReturn.class)) { // 执行业务逻辑 NewUseInsideMethods insideMethods = new NewUseInsideMethods(); StudentOldTesting param = new StudentOldTesting(); param.setName("testName"); StudentOldTestingReturn result = insideMethods.OldLogicTesting(param); // 验证构造方法确实被调用了 Assertions.assertEquals(1, mockedBatch.constructed().size()); Assertions.assertEquals(1, mockedReturn.constructed().size()); // 验证setter确实被调用 StudentOldTestingReturn returnMock = mockedReturn.constructed().get(0); Mockito.verify(returnMock).setId("mockId"); Mockito.verify(returnMock).setName("testName"); } } }
方案2:改造业务代码提升可测试性(更推荐的长期方案)
把方法内部需要实例化的类作为依赖注入,或者提供工厂类来创建对象,避免在业务方法里硬编码new对象:
// 改造后的业务类 public class NewUseInsideMethods { // 把需要创建的对象通过Setter注入进来,或者用构造注入 private Supplier<StudentOldTestingReturn> returnSupplier = StudentOldTestingReturn::new; private Supplier<OldBatchName> batchNameSupplier = OldBatchName::new; public void setReturnSupplier(Supplier<StudentOldTestingReturn> returnSupplier) { this.returnSupplier = returnSupplier; } public void setBatchNameSupplier(Supplier<OldBatchName> batchNameSupplier) { this.batchNameSupplier = batchNameSupplier; } public StudentOldTestingReturn OldLogicTesting(StudentOldTesting Student) { StudentOldTestingReturn sturentReturn = returnSupplier.get(); OldBatchName batchName = batchNameSupplier.get(); batchName.setId("1"); batchName.setName("test"); sturentReturn.setId(batchName.getId()); sturentReturn.setName(Student.getName()); return sturentReturn; } }
改造后测试的时候直接把Mock对象的Supplier注入即可,不需要用特殊的Mock构造能力,兼容性更好。
问题2:Eclipse测试跑通但Jacoco覆盖率为0的常见解决方法
- 检查Jacoco插件配置:如果是Maven项目,确认
jacoco-maven-plugin已经绑定到test和report生命周期,配置示例:
<plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.11</version> <executions> <execution> <goals> <goal>prepare-agent</goal> </goals> </execution> <execution> <id>report</id> <phase>test</phase> <goals> <goal>report</goal> </goals> </execution> </executions> </plugin>
- 检查测试类和源码类的包路径是否一致:测试类要和被测类放在同一个包名下(src/test/java和src/main/java的包结构要完全对应),否则Jacoco可能识别不到对应关系
- 检查是否有配置排除了被测类:查看pom里的Jacoco配置有没有
<excludes>标签把你的Mapper类排除了 - 不要用PowerMock:PowerMock会修改字节码和Jacoco的插桩冲突,如果必须用PowerMock要配置 offline instrumentation
- 执行测试前先clean:每次生成覆盖率报告前先执行
mvn clean test,避免旧的class文件影响统计结果
内容的提问来源于stack exchange,提问作者shraban rana
相关产品推荐
相关产品推荐

