JUnit技术问题:Mockito Mock私有方法方案及ArgumentMatchers报错解决
解决JUnit测试中的两个问题
问题2:修复「不能在存根外使用ArgumentMatchers」错误
错误原因
你这段代码的核心问题是:你在真实的FileViewerService实例(@InjectMocks注入的是真实对象,未配合@Spy)上调用了Mockito.when()存根方法。Mockito.when()仅能用于Mock对象或Spy对象,直接在真实实例上使用就会抛出该错误。而且你的测试逻辑完全没必要存根fetchNodes——你本来就是要测试这个方法的真实逻辑,存根它等于跳过真实代码执行,测试毫无意义。
修正方案
直接移除存根代码,构造合法输入参数,调用真实的fetchNodes方法,再断言返回结果是否符合预期。如果transformDataMap私有方法依赖MultipartFile的某些行为,只需要MockMultipartFile的对应方法即可。
修正后的测试代码:
@InjectMocks private FileViewerService fileViewerService; @Mock private MultipartFile multipartfile; @Test public void test_fetchNodes() throws Exception { // 准备测试数据 String content = "content"; String fileType = "TXT"; // Mock MultipartFile的必要方法 Mockito.when(multipartfile.getOriginalFilename()).thenReturn("test.txt"); // 调用真实方法 List<String> resultPNodes = fileViewerService.fetchNodes(multipartfile, content, fileType); // 根据transformDataMap的实际逻辑断言结果,示例假设会生成两个节点 assertEquals(2, resultPNodes.size()); assertTrue(resultPNodes.contains("parentnode1")); assertTrue(resultPNodes.contains("parentnode2")); }
问题1:私有方法transformDataMap的Mock与测试覆盖率处理
情况1:Mock私有方法transformDataMap
Mockito本身不支持Mock私有方法,需要借助PowerMock实现,步骤如下:
- 引入匹配JUnit版本的PowerMock依赖(JUnit4对应
powermock-module-junit4,JUnit5对应powermock-module-junit5) - 在测试类上添加注解:
@RunWith(PowerMockRunner.class)(JUnit4)或对应JUnit5的注解,同时添加@PrepareForTest(FileViewerService.class),告知PowerMock修改该类字节码 - 使用
PowerMockito.when()Mock私有方法
示例代码:
@RunWith(PowerMockRunner.class) @PrepareForTest(FileViewerService.class) public class FileViewerServiceTest { @InjectMocks private FileViewerService fileViewerService; @Mock private MultipartFile multipartfile; @Test public void test_fetchNodes_withMockPrivateMethod() throws Exception { String content = "content"; String fileType = "TXT"; List<String> mockParentNodes = Arrays.asList("mockNode1", "mockNode2"); // Mock私有方法transformDataMap,直接修改传入的parentNodes参数 PowerMockito.doAnswer(invocation -> { List<String> parentNodes = invocation.getArgument(4); parentNodes.addAll(mockParentNodes); return null; }).when(fileViewerService, "transformDataMap", multipartfile, content, fileType, any(Map.class), any(), any(List.class)); // 调用方法 List<String> result = fileViewerService.fetchNodes(multipartfile, content, fileType); // 断言结果 assertEquals(mockParentNodes, result); } }
情况2:不Mock私有方法,获取测试覆盖率
如果不想Mock私有方法,直接测试fetchNodes的真实逻辑即可,主流覆盖率工具(如JaCoCo)会自动统计私有方法的执行情况——只要测试用例执行到私有方法的代码,就会被计入覆盖率。
具体做法:
- 构造能触发
transformDataMap不同分支逻辑的输入(比如不同文件内容、文件类型) - 调用
fetchNodes方法,断言返回结果符合transformDataMap的处理逻辑 - 生成覆盖率报告时,JaCoCo会将
transformDataMap的代码执行情况纳入统计
比如若transformDataMap会根据fileType=TXT的内容解析出特定节点,你就构造对应的content值,调用方法后断言返回的parentNodes与预期一致,这样私有方法的代码被执行,覆盖率自然会被统计。
内容的提问来源于stack exchange,提问作者isagirl
相关产品推荐
相关产品推荐

