如何为返回MongoDB名称的方法编写JUnit,解决SONAR覆盖率未覆盖问题
问题排查及修正方案
1. 现有测试代码的问题点
- 错误Mock了待测试的业务类本身:
Mock (mongoDboperation)这行逻辑错误,你要验证的是mongoDboperation的真实方法逻辑,Mock之后调用的都是代理假方法,自然不会走真实业务代码,SONAR无法识别到覆盖 - 链式调用的Mock层级缺漏:
mongoConnectionDetails.getMongoDatabase().getName()是连续调用,你只Mock了mongoConnectionDetails,没有Mock它返回的MongoDatabase对象,测试运行会直接抛空指针异常,根本无法正常执行,自然没有覆盖率 - 断言逻辑错误:你打桩返回的固定值是
dbName,断言却比对不相关的actualDBname,就算测试跑通也会断言失败 - 没有完成依赖注入:
mongoConnectionDetails是业务类里通过@Autowired注入的依赖,你Mock之后没有将Mock对象注入到业务类实例中,业务类里的依赖还是空值,运行会抛空指针
2. 修正后的测试代码示例(以JUnit 5 + Mockito为例)
import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import static org.mockito.Mockito.when; import static org.junit.jupiter.api.Assertions.assertEquals; // 启用Mockito注解能力 @ExtendWith(MockitoExtension.class) public class MongoDbOperationTest { // Mock注入的依赖对象 @Mock private MongoConnectionDetails mongoConnectionDetails; // Mock链式调用的中间返回对象 @Mock private MongoDatabase mongoDatabase; // 待测试的真实业务实例,Mockito会自动把上面的Mock对象注入进去 @InjectMocks private MongoDbOperation mongoDboperation; @Test public void testGetMongoDBName() throws Exception { // 给第一层调用打桩 when(mongoConnectionDetails.getMongoDatabase()).thenReturn(mongoDatabase); // 给第二层调用打桩 when(mongoDatabase.getName()).thenReturn("expectedDbName"); // 调用真实业务方法 String output = mongoDboperation.getMongoDBName(); // 断言结果和预期一致 assertEquals("expectedDbName", output); } }
如果使用的是JUnit 4,只需要把类上的注解替换为@RunWith(MockitoJUnitRunner.class即可,其余逻辑保持一致。
3. 额外排查点
- 确保测试类和业务类在同一项目的groupId路径下,SONAR才能正确关联覆盖率数据
- 扫描SONAR前先执行完整的测试构建命令(Maven项目执行
mvn clean test,Gradle项目执行gradle clean test),生成最新的覆盖率报告后再提交扫描
内容的提问来源于stack exchange,提问作者R Madhavan
相关产品推荐
相关产品推荐

