单元测试中如何mock私有方法返回值以完成findById方法测试
问题说明
现有服务类方法如下:
public List<ProductDTO> findById(final int id) { final List<String> categoryList = getCategoryById(id); final List<UUID> productUuidList = productRepository.findAllUuidByCategoryIdIn(categoryList); return getProductDTOList(); } private static List<String> getCategoryById(final int id) { // 省略内部实现 return ... }
单元测试代码如下:
@Test public void test_findByZoneOffset() { List<String> categoryList = new ArrayList<>(); // 省略构造categoryList的逻辑 final List<UUID> productUuidList = new ArrayList<>(); for (int i = 0; i < 10; i++) { productUuidList.add(UUID.randomUUID()); } when(productRepository.findAllUuidByCategoryIdIn(categoryList)) .thenReturn(productUuidList); // 省略其他逻辑 final List<ProductDTO> productDTOList = productService.findById(5); }
遇到的问题:无法构造出和私有方法getCategoryById返回值完全一致的categoryList,该私有方法内部没有调用其他外部依赖,不希望在单元测试中直接调用该私有方法,想要mock一个categoryList让findById运行时获取到的就是mock的内容,该如何实现?
实现方案
可以通过PowerMock框架mock私有静态方法的返回值实现需求,操作步骤如下:
- 首先引入PowerMock和Mockito的整合依赖,匹配你项目的JDK、Spring版本即可。
- 给测试类添加如下注解:
@RunWith(PowerMockRunner.class) @PrepareForTest(你的服务类.class) // 替换为你实际的服务类类名 - 修改测试用例,对私有静态方法打桩,示例代码如下:
@Test public void test_findByZoneOffset() { // 自定义你需要的mock返回值 List<String> mockCategoryList = Arrays.asList("分类1", "分类2", "分类3"); // 对服务类的静态方法进行spy PowerMockito.spy(你的服务类.class); // 当私有静态方法getCategoryById入参为5时,返回我们构造的mockCategoryList PowerMockito.doReturn(mockCategoryList) .when(你的服务类.class, "getCategoryById", 5); // 原有repository打桩逻辑直接用mockCategoryList即可 final List<UUID> productUuidList = new ArrayList<>(); for (int i = 0; i < 10; i++) { productUuidList.add(UUID.randomUUID()); } when(productRepository.findAllUuidByCategoryIdIn(mockCategoryList)) .thenReturn(productUuidList); // 调用测试方法 final List<ProductDTO> productDTOList = productService.findById(5); // 后续添加你的断言逻辑即可 }
如果不想引入PowerMock这类修改字节码的测试框架,更规范的改造方式是将getCategoryById方法抽为独立工具类的公共方法,之后直接mock该工具类的方法返回值即可,更符合可测性设计要求。
内容的提问来源于stack exchange,提问作者user16409822
相关产品推荐
相关产品推荐

