如何为重写方法编写JUnit测试?重写方法测试覆盖率无法提升问题排查
为什么你的重写方法覆盖率上不去?
我一眼就看出问题所在了——你的测试代码完全没执行到你在handler()里重写的handleMessage方法!
你看,你在测试里做了这几件事:
- 创建了一个Mockito spy的
MessageHandler对象hand - 对这个spy对象做了
doNothing().when(hand).handleMessage(any(Message.class))的 stub - 调用了
hand.handleMessage(message)
但你获取的processAchServiceImp.handler()返回的匿名内部类实例handler,从头到尾根本没被调用过!这两个是完全独立的对象,所以你的业务逻辑一行都没跑,覆盖率当然上不去。
正确的测试写法
我们需要直接调用业务代码返回的那个匿名内部类实例的handleMessage方法,同时mock掉它依赖的外部组件(比如sftpGetAway、processFile、日志),避免测试依赖外部资源。
核心步骤
- 获取业务方法返回的真实
MessageHandler实例,而不是自己mock/spy一个无关对象 - 构造符合业务逻辑要求的
Message(payload必须是File类型,因为代码里做了强转) - Mock掉外部依赖(如SFTP服务、后续处理方法),聚焦测试
handleMessage的分支逻辑 - 调用
handleMessage并验证逻辑执行是否符合预期
修改后的完整测试代码
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.messaging.Message; import org.springframework.messaging.support.MessageBuilder; import org.junit.jupiter.api.extension.ExtendWith; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) public class ProcessAchServiceTest { @Mock private SftpGetAway sftpGetAway; // 替换成你的SFTP服务类 @InjectMocks private ProcessAchServiceImp processAchServiceImp; // 你的业务服务实现类 @TempDir Path tempDir; // JUnit自动管理的临时目录,用于创建测试文件 @Test public void testHandleMessage_WithAchFile() throws IOException { // 1. 创建测试用的ACH文件并写入内容 File achFile = tempDir.resolve("ACH_test_file.txt").toFile(); Files.writeString(achFile.toPath(), "field1; field2; field3"); // 2. 构造符合要求的Message对象 Message<?> message = MessageBuilder.withPayload(achFile) .setHeader("SOME_HEADER_KEY", "SOME_HEADER_VALUE") .build(); // 3. 获取业务代码返回的真实Handler实例 MessageHandler handler = processAchServiceImp.handler(); // 4. 调用重写的handleMessage方法 handler.handleMessage(message); // 5. 验证逻辑分支是否正确执行 verify(sftpGetAway, times(1)).sendToSftpUploaded(achFile); verify(processAchServiceImp, times(1)) .processFile("ACH_test_file.txt", List.of("field1", "field2", "field3")); } @Test public void testHandleMessage_WithNonAchFile() throws IOException { // 1. 创建非ACH测试文件 File nonAchFile = tempDir.resolve("REGULAR_test_file.txt").toFile(); Files.writeString(nonAchFile.toPath(), "fieldA; fieldB"); // 2. 构造Message对象 Message<?> message = MessageBuilder.withPayload(nonAchFile) .setHeader("SOME_HEADER_KEY", "SOME_HEADER_VALUE") .build(); // 3. 获取真实Handler实例并调用方法 MessageHandler handler = processAchServiceImp.handler(); handler.handleMessage(message); // 4. 验证非ACH分支逻辑 verify(sftpGetAway, times(1)).sendToSftpNonUploaded(nonAchFile); verify(processAchServiceImp, times(1)) .processFile("REGULAR_test_file.txt", List.of("fieldA", "fieldB")); } }
关键细节说明
- @TempDir的作用:自动创建和清理临时文件,避免测试残留,保证测试环境独立
- Mock外部依赖的原因:我们要测试的是
handleMessage的分支判断逻辑,而非SFTP上传、文件处理的真实业务,mock后能聚焦核心逻辑 - 双分支测试:分别测试文件名以
ACH开头和非开头的场景,确保所有代码路径都被覆盖
这样写完之后,你的重写方法的每一行代码都会被执行到,覆盖率自然就提上去了!
内容的提问来源于stack exchange,提问作者Abraham Macias
相关产品推荐
相关产品推荐

