1. 程式人生 > >單元測試框架PowerMock

單元測試框架PowerMock

1.概述

Mockito 是一個針對 Java 的單元測試模擬框架,它與 EasyMock 和 jMock 很相似,都是為了簡化單元測試過程中測試上下文的搭建而開發的工具。
  PowerMock 也是一個單元測試模擬框架,它是在其它單元測試模擬框架的基礎上做出的擴充套件。通過提供定製的類載入器以及一些位元組碼篡改技巧的應用,PowerMock 現了對靜態方法、構造方法、私有方法以及 Final 方法的模擬支援,對靜態初始化過程的移除等強大的功能。

2.引入依賴

		<dependency>
			<groupId>org.powermock</groupId>
			<artifactId>powermock-api-mockito</artifactId>
			<version>1.7.4</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.powermock</groupId>
			<artifactId>powermock-module-junit4</artifactId>
			<version>1.7.4</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-all</artifactId>
			<version>1.8.5</version>
		</dependency>

3.程式碼示例

單元測試用到的類:

public interface StudentDao {
	String queryStudent();
}

public interface StudentService {
	
	public String selectStudentByName();
	
	public String selectStudentByName2();
}

@Repository
public class StudentDaoImpl implements StudentDao {

	@Override
	public String queryStudent() {
		
		return "拿著核武器的程式設計師";
	}

}

@Service
public class StudentServiceImpl implements StudentService {

	@Autowired
	private StudentDao studentDao;

	// 正常方法
	@Override
	public String selectStudentByName() {
		// 呼叫了私有方法
		String student = getNameById();
		System.out.println("method:selectStudentByName" + student);
		return student;
	}

	// 正常方法
	@Override
	public String selectStudentByName2() {
		String name = StudentServiceImpl.selectStudentById();
		System.out.println("靜態方法返回值:" + name);
		return name;
	}

	// 靜態方法
	public static String selectStudentById() {
		System.out.println("------------------");
		return "拿著大炮的男孩";
	}

	private String getNameById() {
		String student = studentDao.queryStudent();
		System.out.println("method:getNameById" + student);
		return student;
	}

	public final String getAgeById() {
		System.out.println("----------------");
		return "拿著大炮的男孩";
	}
}

單元測試類:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ StudentServiceImpl.class })
public class StudentServiceTest {

	/**
	 * spy()方法:表示區域性mock,執行方法的時候會進入具體的方法內,spy的作用是讓被測類正常工作,但是可以攔截某些方法的返回值
	 * 比如讓StudentServiceImpl中的selectStudentByName()正常工作,但是返回值可以是我們期望的值
	 * mock()方法:表示全域性mock,執行方法的時候不會進入到具體方法內
	 */

	/**
	 * 使用powermock的測試類需要加@RunWith(PowerMockRunner.class)
	 * 若需要模擬建構函式、私有方法、static方法、final方法都需要在測試類上添加註解
	 * 
	 * @throws Exception
	 * @PrepareForTest({ 被Mock的類 })
	 * 
	 *  1.測試私有方法
	 */
	@Test
	public void test() throws Exception {
		// 區域性mock
		StudentServiceImpl serviceImpl = PowerMockito.spy(new StudentServiceImpl());
		// 在selectStudentByName中呼叫了私有方法,此時需要對私有方法mock
		// 若有引數,就在後面使用Mockito.anyXxx()
		// 由於私有方法中又使用了自動注入的StudentDao,所以mock StudentDao然後通過Whitebox(白盒)替換屬性
		StudentDao studentDao = PowerMockito.mock(StudentDao.class);
		// 第一個引數:需要被替換屬性的物件 ;第二個引數:屬性名 ; 第三個引數:屬性值
		Whitebox.setInternalState(serviceImpl, "studentDao", studentDao);
		PowerMockito.doReturn("hahahaha").when(studentDao).queryStudent();
		PowerMockito.when(serviceImpl, "getNameById").thenReturn("東皇太一");
		serviceImpl.selectStudentByName();
	}

	/**
	 * 2.測試靜態方法 
	 * 想要單元測試selectStudentByName2()方法,但是該方法中使用了靜態方法
	 */
	@Test
	public void test2() {
		// 模擬靜態方法前需要先呼叫這一句,不寫會報錯!!!
		PowerMockito.mockStatic(StudentServiceImpl.class);
		// 模擬當執行靜態方法StudentServiceImpl.selectStudentById()時候,返回123(模擬的返回值)
		PowerMockito.when(StudentServiceImpl.selectStudentById()).thenReturn("123");
		StudentServiceImpl serviceImpl = PowerMockito.spy(new StudentServiceImpl());
		serviceImpl.selectStudentByName2();
	}

	/**
	 * 3.測試final方法
	 */
	@Test
	public void test3() {
		StudentServiceImpl service = PowerMockito.mock(StudentServiceImpl.class);
		PowerMockito.when(service.getAgeById()).thenReturn("18");
		String age = service.getAgeById();
		System.out.println(age);
	}
}