当前位置:网站首页>PowerMock for Systematic Explanation of Unit Testing
PowerMock for Systematic Explanation of Unit Testing
2022-08-11 09:04:00 【After dark】
单元测试系统化讲解之PowerMock
- 什么是PowerMock
- Mock局部变量
- Mock静态方法
- Mock final 修饰的方法
- Mock私有方法
- Verify的使用
- Mock不同的构造函数
- Parameters Matcher接口的使用
- Answer接口的使用
- Spy的使用
一、什么是PowerMock
1.1 前述
本次讲解的PowerMockIt is an advanced technical framework for unit testing;所以学习PowerMock中,Bloggers assume that you have met the following conditions:
- Know what unit testing is
- 明白Junit/MockitoSome relevant use or knowledge
- Want to learn some techniques related to unit testing
PowerMock是什么?
- PowerMock是一个扩展了其它如EasyMock等mock框架的、功能更加强大的框架.PowerMock使用一个自定义类加载器和字节码操作来模拟静态方法、构造方法、final类和方法、私有方法、去除静态初始化器等等.
- 通过使用自定义的类加载器,简化采用的IDE或持续集成服务器不需要做任何改变.
- 熟悉PowerMock支持的mock框架的开发人员会发现PowerMock很容易使用,因为对于静态方法和构造器来说,整个的期望API是一样的.
- PowerMock旨在用少量的方法和注解扩展现有的API来实现额外的功能.目前PowerMock支持EasyMock和Mockito.
- PowerMockis based on otherMock框架,做的增强.So it can't be used alone.
PowerMock解决了哪些痛点?
- 现如今比较流行的Mock工具如jMock,EasyMock,Mockito等都有一个共同的缺点:不能mock静态、final、私有方法等.而PowerMock能够完美的弥补以上三个Mock工具的不足.
- 能够mock方法内
new 出来的对象
注意:为什么总说PowerMock尽量少用?
- PowerMockis a very powerful and useful tool. 但是,It should only be used when absolutely necessary,Because it can have a huge impact on test execution time.
- 缺乏API知识,Overly restrictive visibility and direct static method calls.
- If you find your test code base fullPowerMock的用法,It is recommended that you try the above methods to get rid of them.
- If there are too many unnecessary unit testsPowerMockito使用,Then the quality of this unit test is to be considered,In particular, some private methods should not be used as much as possiblePowerMockito,善PowerMockito,Try to maximize the fidelity of unit tests.
1.2 PowerMock快速入门
PowerMock有两个重要的注解,分别是:
@RunWith(PowerMockRunner.class) @PrepareForTest( { YourClassWithEgStaticMethod.class })使用了
@PrepareForTest注解,能够使用PowerMock的强大功能(mock静态、final、私有方法等);需要注意的是,It cannot work alone,We have to add both@RunWith(PowerMockRunner.class)使用PowerMock的依赖项:
<dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>1.6.5</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito</artifactId> <version>1.6.5</version> <scope>test</scope> </dependency>开始测试:
Write the class to be tested:
public class UserService{ private UserDao userDao; public UserService(UserDao userDao){ this.userDao = userDao; } public int querUserCount(){ return userDao.getCount(); } public void saveUser(User user){ userDao.insertUser(user); } }测试类:
public class UserServiceTest{ private UserService userService; @Before public void setUp(){ userService = new UserService(new UserDao()); } @Mock private UserDao userDao; @Test public void testQueryUserCountWithPowerMock(){ UserDao uDao = PowerMockito.mock(UserDao.class); PowerMockito.when(uDao.getCount()).thenReturn(10); UserService service = new UserService(uDao); int result = service.queryUserCount(); assertEquals(10,result); } @Test public void testQueryUserCountWithMockito(){ MockitoAnnotations.initMocks(this); UserService service = new UserService(userDao); Mockito.when(userDao.getCount()).thenReturn(10); int result = service.queryUserCount(); assertEquals(10,result); } @Test public void testSaveUserWIthJunit(){ try{ userService.saveUser(new User()); fail("should not process to here"); }catch (Exception e){ assertTrue(e instanceof UnsupportedOperationException); } } }
代码中展示了Junit、mockito、powermockthree test methods.
二、PowerMock实战演示
2.1 Use local variables inside methods
- 被测试类:
public class UserService{
public int queryUserCount(){
UserDao userDao = new UserDao();
return userDao.getCount();
}
public void saveUser(User user){
UserDao userDao = new userDao();
userDao.insertUser(user);
}
}
- 测试类
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest{
@Test
public void tesetQueryUserCount(){
try{
UserService userService = new UserService();
UserDao userDao = mock(UserDao.class);
whenNew(UserDao.class).withNoArguments().thenReturn(userDao);
doReturn(10).when(userDao).getCount();
int result = userService.queryUserCount();
assertEquals(10,result);
}catch(Throwable e){
fail();
}
}
@Test
public void testSaveUser(){
try{
User user = new User();
UserService userService = new UserService();
UserDao userDao = mock(UserDao.class);
whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
userService.saveUser(user);
Mockito.verify(userDao,Mockito.times(1)).insertUser(user);
}catch(Throwable e){
fail();
}
}
}
2.2 Mock静态方法
- 静态Dao层
public class UserDao{
public static int getCount(){
throw new UnsupportedOperationException();
}
public static void insertUser(User user){
throw new UnsupportedOperationException();
}
}
- 被测试的Service层
public class UserService{
public int queryUserCount(){
return UserDao.getCount();
}
public void saveUser(User user){
UserDao userDao = new UserDao();
UserDao.insertUser(user);
}
}
- 测试类
@RunWith(PowerMockRunner.class)
@PrepareForTest({
UserService.class,UserDao.class})
public class UserServiceTest{
@Test
public void testQueryUserCount() throws Exception{
PowerMockito.mockStatic(UserDao.class);
PowerMockito.when(UserDao.getCount()).thenReturn(10);
UserService userService = new UserService();
int result = userService.queryUserCount();
assertEquals(10,result);
}
@Test
public void testSaveUser() throws Exception{
mockStatic(UserDao.class);
User user = new User();
doNoting().when(UserDao.class);
UserService userService = new UserService();
userService.saveUser(user);
PowerMockito.verifyStatic();
}
}
2.3 final 修饰的类
- final 类
final public class UserDao{
public int getCount(){
throw new UnsupportedOperationException();
}
public void insertUser(User user){
throw new UnsupportedOperationException();
}
}
- Service类
public class UserService{
private UserDao userDao;
public UserService(UserDao userDao){
this.userDao = userDao;
}
public int queryUserCount(){
return userDao.getCount();
}
public void saveUser(User suer){
userDao.insertUser(user);
}
}
- 测试类
@RunWith(PowerMockRunner.class)
@PrepareForTest({
UserService.class,UserDao.class})
public class UserServiceTest{
@Test
public void testQueryUserCountWithPowerMock() throws Exception{
UserDao uDao = PowerMockito.mock(UserDao.class);
System.out.println(uDao.getClass());
PowerMockito.when(uDao.getCount()).thenReturn(10);
UserService userService = new UserService(uDao);
int result = userService.queryUserCount();
assertEquals(10,result);
}
}
2.4 verify的使用
- UserDao类
public class UserDao{
public int getCount(User user){
throw new UnsupportedOperationException();
}
public void updateUser(User user){
throw new UnsupportedOperationException();
}
public void insertUser(User user){
throw new UnsupportedOperationException();
}
}
- UserService
public class UserService{
public void saveOrUpdate(User user){
UserDao userDao = new UserDao();
if(userDao.getCount(user) > 0){
userDao.updateUser(user);
}else{
userDao.insertUser(user);
}
}
}
- UserServiceTest
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserSErviceTest{
@Test
public void testSaveOrUpdateWillUseNewJoiner() throw Exception {
User user = PowerMockito.mock(User.class);
UserDao userDao = PowerMockito.mock(UserDao.class);
PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(user);
PowerMockito.when(userDao.getCount(user)).thenReturn(0);
UserService userService = new UserService();
userService.saveOrUpdate(user);
}
@Test
public void testSaveOrUpdateWillUseUpdateOriginal() throw Exception{
User user = PowerMockito.mock(User.class);
UserDao userDao = PowerMockito.mock(userDao.class);
PowerMockito.whenNew(UserDao.class).withAnyArguments().thenRetuurn(userDao);
PowerMockito.when(userDao.getCount(user)).thenReturn(1);
UserService userService = new UserService();
userService.saveOrUpdate(user);
Mockito.verify(userDao).insertUser(user);
Mockito.verify(userDao,Mockito.never()).updateUser(user); // neverIndicates that it will not be executed once
}
}
verify有很多方法,Students can look at the source code or official documents to use and practice;
2.5 Mock 构造函数
- UserDao
public class UserDao{
private String username;
private String password;
public UserDao(String username,String password){
this.username = username;
this.password = password;
}
public void insert(){
throw new UnsupportedOperationException();
}
}
- UserService
public class UserService{
public void save(String username, String password){
UserDao userDao = new UserDao(username,password);
userDao.insert();
}
}
- UserServiceTest
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest{
@Test
public void testSave() throws Exception(){
UserDao userDao = PowerMockito.mock(UserDao.class);
String username = "anyu";
String passsword = "lyle";
PowerMocktio.whenNew(UserDao.class).withArguments(username,passsword).thenReturn(userDao);
PowerMockito.doNoting().when(userDao).insert();
UserService userService = new UserService();
Mockito.verify(userDao).insert();
}
}
2.6 Arguments Matcher的使用
- UserDao
public class UserDao{
public String queryByName(String username){
throw new UnsupportedOperationException();
}
}
- UserService
public class UserService{
public String find(String name){
UserDao userDao = new UserDao();
return userDao.queryByName(name);
}
}
- UserServiceTest
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest{
@Test
public void testFind() throws Exception{
UserDao userDao = PowerMockito.mock(UserDao.class);
PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
PowerMockito.when(userDao.queryByName("lyle")).thenReturn("anyu");
UserService service= UserService();
String result = service.find("lyle");
assertEquals("anyu",result);
PowerMockito.when(userDao.queryByName("Jacky")).thenReturn("anyu");
UserService service= UserService();
String result = service.find("lyle");
assertEquals("anyu",result);
PowerMockito.when(userDao.queryByName("Tommy")).thenReturn("anyu");
UserService service= UserService();
String result = service.find("lyle");
assertEquals("anyu",result);
}
// 使用match
@Test
public void testFindWithMatcher() throw Exception{
UserDao userDao = PowerMockito.mock(UserDao.class);
PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao); //CSDN:暗余
PowerMockito.when(userDao.queryByName(Matchers.argThat(new MyArgumentMatcher()))).thenReturn("anyu");
UserService service = new UserService();
assertEquals("lyle",service.find("lyle"));
assertEquals("lyle",service.find("Jacky"));
assertEquals("lyle",service.find("Van"));
assertEquals("lyle",service.find("Tony"));
}
static class MyargumentMatcher extends ArgumentMatcher<String>{
@Override
public boolean matches(Object o){
String arg = (String) o;
switch(arg){
case "lyle":
case "Jacky":
case "Van":
case "Tony":
return true;
default:
return false;
}
}
}
}
2.7 Answer 接口的使用
- UserDao
public class UserDao{
public String queryByName(String username){
throw new UnsupportedOperationException();
}
}
- UserService
public class UserService{
public String find(String name){
UserDao userDao = new UserDao();
return userDao.queryByName(name);
}
}
- UserServiceTest
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserService.class)
public class UserServiceTest{
@Test
public void testFindWithAnswer() throw Exception{
UserDao userDao = PowerMockito.mock(UserDao.class);
PowerMockito.whenNew(UserDao.class).withAnyArguments().thenReturn(userDao);
PowerMockito.when(userDao.queryByName(Mockito.anyString())).then(invocation -> {
String arg = (String) invocation.getArguments()[0];
switch(arg){
case "lyle":
return "I am csdn 暗余";
case "Alex":
return "I am alex";
default:
throw new RuntimeException("Not support "+ arg);
}
});
UserService service = new UserService();
assertEquals("I am casn 暗余",service.find("lyle"));
assertEquals("I am alex", service.find("Alex"));
}
}
2.8 Spy的使用
- UserService
public class UserService{
public void foo(){
log();
}
private void log(){
System.out.println("I am console log.");
}
public boolean exist(String username){
return checkExist(username);
}
private boolean checkExist(String username){
throw new UnsupportedOperationException();
}
}
使用spy会调用真实的方法:

如果使用了whenThe function specifies the request parameters of the corresponding method,Called when the corresponding request parameters are passed inmockThe method does not print anything;

而不满足条件,will continue to execute the real method:

测试私有方法:
public class UserServiceTest{
@Test
public void testCheck() throws Exception{
UserService userService = PowerMockito.apy(new UserService());
PowerMockito.doReturn(true).when(userService,"checkExist","lyle");
assertTrue(userService.exist("lyle"));
userService.exist("other");
}
}
写文不易,觉得不错点个赞再走吧~ ^^
边栏推荐
- 关于ts的一些泛型关键字用法
- Lightweight network (1): MobileNet V1, V2, V3 series
- 【wxGlade学习】wxGlade环境配置
- golang 字符串操作
- Openlayers Aggregate Graph, Weight Aggregate Graph, and Aggregate Graph Click Events
- IPQ4019/IPQ4029 support WiFi6 MiniPCIe Module 2T2R 2×2.4GHz 2x5GHz MT7915 MT7975
- YTU 2297: KMP模式匹配 三(串)
- [UEFI]EFI_DEVICE_PATH_PROTOCOL 结构体初始化的一个例子
- SDUT 2877:angry_birds_again_and_again
- Typescrip编译选项
猜你喜欢

新一代开源免费的轻量级 SSH 终端,非常炫酷好用!

基于C#通过PLCSIM ADV仿真软件实现与西门子1500PLC的S7通信方法演示

Rust从入门到精通06-函数

代码签名证书可以解决软件被杀毒软件报毒提醒吗?

【wxGlade学习】wxGlade环境配置

Notable NFT development trends in 2022

Unity3D - modification of the Inspector panel of the custom class

Inventorying Four Entry-Level SSL Certificates

对比学习系列(三)-----SimCLR

如何通过 IDEA 数据库管理工具连接 TDengine?
随机推荐
深度学习100例 —— 卷积神经网络(CNN)识别眼睛状态
flex布局回顾
DataGrip配置OceanBase
设置Vagrant创建的虚拟机名称和内存
安装ES7.x集群
Kotlin算法入门求自由落体
UNITY gameobject代码中setacvtive(false)与面板中直接去掉勾 效果不一样
One network cable to transfer files between two computers
dsu on tree(树上启发式合并)学习笔记
Kotlin算法入门求回文数算法优化一
Inventorying Four Entry-Level SSL Certificates
Notable NFT development trends in 2022
JUC Concurrent Programming
自定义卷积核的分组转置卷积如何实现?
中国电子学会五级考点详解(一)-string类型字符串
tar 命令使用
[wxGlade learning] wxGlade environment configuration
[UEFI]EFI_DEVICE_PATH_PROTOCOL 结构体初始化的一个例子
Halcon算子解释
SDUT 2877:angry_birds_again_and_again