采用powermock书写java UT.
pom文件引入相关依赖
<!-- PowerMock JUnit 4.4+ Module -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<!-- PowerMock Mockito2 API -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
复制代码
相关注解说明
// 告诉JUnit使用PowerMockRunner进行测试
@RunWith(PowerMockRunner.class)
// 所有需要测试的类列在此处,适用于模拟final类或有final, private, static, native方法的类
@PrepareForTest({RandomUtil.class})
//忽略的程序包中的类(不加载指定包); 常用于解决使用powermock后,提示classloader错误
@PowerMockIgnore("javax.management.*")
// 创建一个实例,这个实例可以调用真实代码的方法
@InjectMocks
// 创建了一个全部Mock的实例,所有属性和方法全被置空(0或者null)。
@Mock
复制代码
mock 返回值
// mock期望值
1. PowerMockito.doReturn(expected).when(mockList).get(index);
2. PowerMockito.when(mockList.get(index)).thenReturn(expected);
// mock异常返回
1. PowerMockito.doThrow(new IndexOutOfBoundsException()).when(mockList).get(index);
2. PowerMockito.when(mockList.get(index)).thenThrow(new IndexOutOfBoundsException());
// 无返回值
PowerMockito.doNothing().when(mockList).clear();
//注意:when().thenReturn()模式会执行原方法,而doReturn().when()模式不会执行原方法。
复制代码
校验返回
Mockito.verify(mockList).clear(); //验证是否方法被调用
Mockito.verify(mockList, Mockito.times(1)).clear(); //验证方法的调用次数
复制代码
mock参数
Mockito提供Mockito.anyInt()、Mockito.anyString、Mockito.any(Class clazz)等来表示任意值。
当我们使用参数匹配器时,所有参数都应使用匹配器。 如果要为某一参数指定特定值时,就需要使用Mockito.eq()方法。
实例
对于不同的类或者方法mock的方式。
------MockMapper.class
public interface MockMapper {
public int count(MockModel model);
}
-----MockServiceImpl.class
@Service
public class MockServiceImpl {
@Autowired
private MockMapper mockMapper;
public int count(MockModel model) {
return mockMapper.count(model);
}
public boolean makeFile(String path) {
File file = new File(path);
return file.exists();
}
}
------MockUtil.class
public class MockUtil {
private static final Random random = new Random();
public static int nextInt(int bound) {
return random.nextInt(bound);
}
}
复制代码
mock普通方法
@RunWith(PowerMockRunner.class)
@PrepareForTest({MockUtil.class})
@PowerMockIgnore("javax.management.*")
public class MockExample {
// 将@Mock注解的示例注入进来
@InjectMocks
private MockServiceImpl mockService;
@Mock
private MockMapper mockMapper;
/**
* mock普通方法
*/
@Test
public void testSelectAppAdvertisementList() {
MockModel model = new MockModel();
PowerMockito.when(mockMapper.count(model)).thenReturn(2);
Assert.assertEquals(2, mockService.count(model));
}
}
复制代码
Mock静态方法
- 声明:
PowerMockito.mockStatic(Class clazz);
PrepareForTest({Class clazz});
复制代码
- 使用
@RunWith(PowerMockRunner.class)
@PrepareForTest({MockUtil.class})
@PowerMockIgnore("javax.management.*")
public class MockStaticExample {
@Test
public void testStaticMethod() {
PowerMockito.mockStatic(MockUtil.class);
PowerMockito.when(MockUtil.nextInt(10)).thenReturn(7);
Assert.assertEquals(7, MockUtil.nextInt(10));
}
}
复制代码
Mock方法内的构造函数
- 声明
- 传指定参数进行构造
PowerMockito.whenNew(*.class).withArguments(argument1, ...).thenReturn(file)
复制代码
- 不管参数进行构造
PowerMockito.whenNew(*.class).withAnyArguments().thenReturn(file)
复制代码
- 使用
public final class FileUtils {
public static boolean isFile(String fileName) {
return new File(fileName).isFile();
}
}
----UT
@RunWith(PowerMockRunner.class)
@PrepareForTest({FileUtils.class})
public class MockStructureExample {
@Test
public void testIsFile() throws Exception {
String fileName = "test.txt";
File file = PowerMockito.mock(File.class);
PowerMockito.whenNew(File.class).withArguments(fileName).thenReturn(file);
PowerMockito.when(file.isFile()).thenReturn(true);
Assert.assertTrue("返回值为假", FileUtils.isFile(fileName));
}
}
复制代码
mock 类的部分方法 spy
如果一个对象,我们只希望模拟它的部分方法,而希望其它方法跟原来一样,可以使用PowerMockito.spy方法代替PowerMockito.mock方法。于是,通过when语句设置过的方法,调用的是模拟方法;而没有通过when语句设置的方法,调用的是原有方法。
- 声明:
PowerMockito.spy(Class clazz); // 类
T PowerMockito.spy(T object); //spy对象
复制代码
- 使用
示例1
public class StringUtils {
public static boolean isNotEmpty(final CharSequence cs) {
return !isEmpty(cs);
}
public static boolean isEmpty(final CharSequence cs) {
return cs == null || cs.length() == 0;
}
}
----UT
@RunWith(PowerMockRunner.class)
@PrepareForTest({ StringUtils.class })
public class StringUtilsTest {
@Test
public void testIsNotEmpty() {
String string = null;
boolean expected = true;
PowerMockito.spy(StringUtils.class);
PowerMockito.when(StringUtils.isEmpty(string)).thenReturn(!expected);
boolean actual = StringUtils.isNotEmpty(string);
Assert.assertEquals("返回值不相等", expected, actual);
}
}
复制代码
示例2 spy对象
public class UserService {
private Long superUserId;
public boolean isNotSuperUser(Long userId) {
return !isSuperUser(userId);
}
public boolean isSuperUser(Long userId) {
return Objects.equals(userId, superUserId);
}
}
---- UT
@RunWith(PowerMockRunner.class)
public class UserServiceTest {
@Test
public void testIsNotSuperUser() {
Long userId = 1L;
boolean expected = false;
UserService userService = PowerMockito.spy(new UserService());
PowerMockito.when(userService.isSuperUser(userId)).thenReturn(!expected);
boolean actual = userService.isNotSuperUser(userId);
Assert.assertEquals("返回值不相等", expected, actual);
}
}
复制代码
mock系统类
注意:由于URLEncoder类是系统类,因此我们应该准备SystemClassUser进行测试,因为这是调用的encode方法的类URLEncoder。 示例1
public class SystemClassUser {
public String performEncode() throws UnsupportedEncodingException {
return URLEncoder.encode("string", "enc");
}
}
---UT
@RunWith(PowerMockRunner.class)
@PrepareForTest( { SystemClassUser.class })
public class SystemClassUserTest {
@Test
public void assertThatMockingOfNonFinalSystemClassesWorks() throws Exception {
mockStatic(URLEncoder.class);
expect(URLEncoder.encode("string", "enc")).andReturn("something");
replayAll();
assertEquals("something", new SystemClassUser().performEncode());
verifyAll();
}
}
复制代码
示例2
public class AppShell {
public Process exec(String command) {
return Runtime.getRuntime().exec(command);
}
}
----UT
@RunWith(PowerMockRunner.class)
@PrepareForTest(AppShell.class)
public class AppShellTest {
@Mock private Runtime mockRuntime;
@Test
public void test() {
PowerMockito.mockStatic(Runtime.class);
when(Runtime.getRuntime()).thenReturn(mockRuntime);
when(mockRuntime.exec()).thenReturn("whatever you want");
// do the rest of your test
}
}
复制代码
mock类的私有方法、属性
- 声明:
- mock私有属性
// 第一种方式; 原生JUnit进行单元测试时使用
ReflectionTestUtils.setField(obj, fieldName, value);
// 第二种方式;Whitebox.setInternalState powermock时使用
Whitebox.setInternalState(obj, fieldName, value);
复制代码
- mock私有方法
1. PowerMockito.stub(PowerMockito.method(UserService.class, "isSuperUser", Long.class)).toReturn(!expected);
2. PowerMockito.when(userService, "isSuperUser", userId).thenReturn(!expected);
复制代码
- 使用
@Service
public class UserService {
@Value("${system.userLimit}")
private Long userLimit;
public Long getUserLimit() {
return userLimit;
}
private boolean isSuperUser(Long userId) {
return Objects.equals(userId, superUserId);
}
}
-----UT
public class UserServiceTest {
@Autowired
private UserService userService;
// mock 私有属性
@Test
public void testGetUserLimit() {
Long expected = 1000L;
ReflectionTestUtils.setField(userService, "userLimit", expected);
// or 下面这一种
// Whitebox.setInternalState(userService, "userLimit", expected);
Long actual = userService.getUserLimit();
Assert.assertEquals("返回值不相等", expected, actual);
}
// mock 私有方法
@Test
public void testIsNotSuperUser() throws Exception {
Long userId = 1L;
boolean expected = false;
UserService userService = PowerMockito.spy(new UserService());
PowerMockito.when(userService, "isSuperUser", userId).thenReturn(!expected);
PowerMockito.stub(PowerMockito.method(UserService.class, "isSuperUser", Long.class)).toReturn(!expected);
boolean actual = userService.isNotSuperUser(userId);
Assert.assertEquals("返回值不相等", expected, actual);
}
}
复制代码