1. 序
2. pom依赖
<dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-testng</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency> |
3. 示例
public class PowermockTest extends PowerMockTestCase { @Mock PowermockDao powermockDao; @InjectMocks PowermockService powermockService = new PowermockService(); @Test public void testSave_正常插入() { final PowermockDto powermockDto = new PowermockDto(); powermockDto.setName("滨江吴彦祖"); // mock根据名称查询返回 PowerMockito.when(powermockDao.getByName(Mockito.anyString())) .thenReturn(null); // mock插入 PowerMockito.doReturn(1) .when(powermockDao) .insert(ArgumentMatchers.argThat(new ArgumentMatcher<PowermockDto>() { @Override public boolean matches(PowermockDto argument) { // 生成ID argument.setId(ThreadLocalRandom.current().nextLong(1)); return true; } })); // 目标方法执行 Assert.assertTrue(powermockService.save(powermockDto) > 0); // 回放目标方法执行,验证方法调用 Mockito.verify(powermockDao).getByName("滨江吴彦祖"); Mockito.verify(powermockDao).insert(powermockDto); } } |
4. 辅助类:
public class PowermockService { private PowermockDao powermockDao; public Integer save(PowermockDto powermockDto) { if (StringUtils.isBlank(powermockDto.getName())) { throw new IllegalArgumentException("名称不能为空"); } final PowermockDto dbPowermockDto = powermockDao.getByName(powermockDto.getName()); if (dbPowermockDto != null) { if (powermockDto.getId() == null || !powermockDto.getId().equals(dbPowermockDto.getId())) { throw new IllegalArgumentException(String.format("名称[%s]重复了", powermockDto.getName())); } } if (powermockDto.getId() == null) { return powermockDao.insert(powermockDto); } else { return powermockDao.update(powermockDto); } } } public interface PowermockDao { PowermockDto getByName(String name); Integer insert(PowermockDto powermockDto); Integer update(PowermockDto powermockDto); } public class PowermockDto { private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof PowermockDto)) return false; PowermockDto that = (PowermockDto) o; if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false; return getName() != null ? getName().equals(that.getName()) : that.getName() == null; } @Override public int hashCode() { int result = getId() != null ? getId().hashCode() : 0; result = 31 * result + (getName() != null ? getName().hashCode() : 0); return result; } } |
5. 使用经验
5.1 mock 静态方法
mockito库并不能mock静态方法,需要依赖powermock
第一步:给类添加注解
// 静态类优先加载,所以需要提前告诉powermock哪些静态类需要mock @PrepareForTest({ PasswordGenerator.class, UserSecurityContext.class }) public class SupplierServiceImplTest extends PowerMockTestCase { } |
第二步:mock使用
@Test(expectedExceptions = BusinessException.class) public void testAddSupplierAccount_genIdentityNoError() { // 告诉powermock,需要mock该类的所有静态方法 PowerMockito.mockStatic(PasswordGenerator.class); final SupplierAccountDto supplierAccountDto = new SupplierAccountDto(); supplierAccountDto.setName("滨江吴彦祖"); supplierAccountDto.setCompanyName("163"); supplierAccountDto.setEmail("wyz@corp.netease.com"); final String randomPWd = "xxxxoooooo"; PowerMockito.when(supplierDao.selectByEmail(anyString())) .thenReturn(new ArrayList<HaitaoSupplier>()); // 静态方法mock PowerMockito.when(PasswordGenerator.genPwd()).thenReturn(randomPWd); PowerMockito.when(pwEncoder.encode(anyString())).thenReturn(randomPWd); PowerMockito.when(identityNoGenerator.genIdentityNo()).thenReturn(-1L); supplierServiceImpl.addSupplierAccount(supplierAccountDto); verify(pwEncoder).encode(randomPWd); } |
5.2 mock void 方法
// void嘛,doNothing顾名思义 PowerMockito.doNothing().when(casService).addSupplier(anyLong(), any(ServiceKey.class)); |
5.3 修改mock方法的入参
PowerMockito.doReturn(1).when(mainSubSupplierApplyDao) .insert(argThat(new ArgumentMatcher<MainSubSupplierApply>() { @Override public boolean matches(MainSubSupplierApply argument) { // mock 插入,生成主键 argument.setId(applyId); return true; } })); |
5.4 修改mock方法的出参
PowerMockito.when(DBEncryptUtil.encrypt(anyString())).thenAnswer(new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { // mock方法返回值,使用第一个入参返回 return invocation.getArgument(0); } }); |
5.5 mock入参null值
// mockito2.x ArgumentMatchers.anyString() 与 ArgumentMatchers.isNull() 互斥,可以看下方法注释 PowerMockito.when(inquiryGoodsSnapshotDao.getBySkuIdsAndPlanSendTimeBetween2Days( ArgumentMatchers.<ObjectPair<String, Long>>anyList(), ArgumentMatchers.<Integer>anyList(), ArgumentMatchers.<Long>isNull()) ).thenReturn(inquiryGoodsSnapshotList); |