当前位置:网站首页>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>
    
  • 开始测试:

    1. 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);
      	}
      }	
      
    2. 测试类:

      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");
	}

}

写文不易,觉得不错点个赞再走吧~ ^^

原网站

版权声明
本文为[After dark]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/223/202208110856459230.html