最近老大讓我寫單元測試,找到這篇文章,閱讀後收穫很多,故轉之。java
《easymock使用準備》
一、引包
在maven的pom.xml加入依賴
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
二、 要測試的類
新建 User類。
public class User {
String type;
}
新建 UserDao接口,裏面有個insertUser(User user)方法。
public interface UserDao {
public boolean insertUser(User user);
}
新建 UserService類,裏面有個registerUser(User user)方法。
public class UserServive {
private UserDao userDao;
public boolean registerUser(User user){
if (user.type.equals("vip")){
return userDao.insertUser(user);
}else {
System.out.println("only vip can be registered!");
Return false;
}
}
}
咱們要測試 UserService的registerUser(User user)方法,可是這個方法依賴於UserDao的insertUser(User user)方法。咱們假設UserDao這個接口如今還沒寫好,可是如今又想測UserService的方法邏輯,可它又依賴於UserDao,這可怎麼測試?這時候就能夠用mock技術啦。
測試代碼以下:
import junit.framework.TestCase;
import static org.easymock.EasyMock.*;
public class UserServiceTest extends TestCase{
private UserDao userDao;
private UserService userService = new UserService();
public void testRegisterUser() {
User user = new User();
user.type = "vip";
userDao = createMock(UserDao.class);
expect(userDao.insertUser(user)).andReturn(true);
replay(userDao);
userService.setUserDao(userDao);
assertEquals(true, userService.registerUser(user));
verify(userDao);
}
}
java單元測試 easyMock 使用總結
EasyMock
java
單元測試
1、 easymock使用準備
引包
在maven的pom.xml加入依賴
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
二、 要測試的類
新建 User類。
public class User {
String type;
}
新建 UserDao接口,裏面有個insertUser(User user)方法。
public interface UserDao {
public boolean insertUser(User user);
}
新建 UserService類,裏面有個registerUser(User user)方法。
public class UserServive {
private UserDao userDao;
public boolean registerUser(User user){
if (user.type.equals("vip")){
return userDao.insertUser(user);
}else {
System.out.println("only vip can be registered!");
Return false;
}
}
}
咱們要測試 UserService的registerUser(User user)方法,可是這個方法依賴於UserDao的insertUser(User user)方法。咱們假設UserDao這個接口如今還沒寫好,可是如今又想測UserService的方法邏輯,可它又依賴於UserDao,這可怎麼測試?這時候就能夠用mock技術啦。
測試代碼以下:
import junit.framework.TestCase;
import static org.easymock.EasyMock.*;
public class UserServiceTest extends TestCase{
private UserDao userDao;
private UserService userService = new UserService();
public void testRegisterUser() {
User user = new User();
user.type = "vip";
userDao = createMock(UserDao.class);
expect(userDao.insertUser(user)).andReturn(true);
replay(userDao);
userService.setUserDao(userDao);
assertEquals(true, userService.registerUser(user));
verify(userDao);
}
}
《easymock使用的通常步驟》
一、 接口/類
easymock class extension的使用方式和普通的interface mock徹底一致,基本上easymock中有的功能easymock class extension都一樣提供,並且全部的類名和方法名都保持一致。
惟一的差別在於,easymock class extension的java package和easymock不一樣,easymock是
org.easymock.*, 而 easymock class extension是org.easymock.classextension.*,典型如
org.easymock.classextension.Easymock 對應 org.easymock.Easymock。另外在發佈時,二者是分開發布的,easymock.jar 和 easymockclassextension.jar,須要根據須要分別導入,或者必要時同時導入。
不過3.0版本已經沒有這個問題,接口與類是同樣的。
《record-replay-verify 模型》
一、建立mock對象
userDao = createMock(UserDao.class);
二、記錄mock對象指望的行爲
expect(userDao.insertUser(user)).andReturn(true);
咱們指望這個mock對象的方法被調用,同時給出咱們但願這個方法返回的結果。這就是所謂的"記錄mock對象上的操做", 同時咱們也會看到"expect"這個關鍵字。總結說,在record階段,咱們須要給出的是咱們對mock對象的一系列指望:若干個mock對象被調用,依從咱們給定的參數,順序,次數等,並返回預設好的結果(返回值或者異常).
三、進入replay階段
replay(userDao);
在replay階段,咱們關注的主要測試對象將被建立,以前在record階段建立的相關依賴被關聯到主要測試對象,而後執行被測試的方法,以模擬真實運行環境下主要測試對象的行爲。
四、對mock對象執行驗證
verify(userDao);
驗證交互行爲,典型如依賴是否被調用,調用的參數,順序和次數等。
《easymock更多使用》
拋出異常
expect(userDao. insertUser (user)).andThrow(new SQLException("ID conflicts!"));
調用次數
調用3次:expect(userDao. insertUser (user)).andReturn(true).times(3);
這裏有一個官網文檔中的例子
expect(mock.voteForRemoval("Document"))
.andReturn((byte) 42).times(3)
.andThrow(new RuntimeException()).times(4)
.andReturn((byte) -42);
對於mock.voteForRemoval("Document")方法的調用,.andReturn((byte) 42).times(3) 代表前3次調用將返回42,.andThrow(new RuntimeException()).times(4)表示隨後的4次調用(第4,5,6,7次)都將拋出異常,andReturn((byte) -42)表示第8次調用時將返回-42。
調用void方法
若是mock對象的方法是void,則須要使用expectLastCall():
userDao.someVoidMethod();
Easymock.expectLastCall();
和Easymock.expect(***)同樣,一樣支持指定調用次數,拋出異常等:
調用次序
Mock對象類型有三種
● Normal — EasyMock.createMock() 默認mock出來的都是這個類型,只關心調用方法的參數,不關心調用的次序。
● Strict — EasyMock.createStrictMock(): 當調用方法有次序要求的時候須要mock這個類型。
● Nice — EasyMock.createNiceMock(): 調用到不指望的方法時不會使測試失敗,若是原方法返回的類型是number的 它就會返回0,若是是boolean 它會返回false,若是是object它會返回null.
參數匹配
// expect(userDao.insertUser(user)).andReturn(true);
expect(userDao.insertUser(EasyMock.<User>anyObject())).andReturn(true);
anyInt()、anyShort()、anyByte()、anyLong()、anyFloat()、anyDouble()、anyBoolean()、 matches(正則表達式)
Capture的使用
若是方法的參數實在沒法預先肯定,咱們可使用capture。好比UserService 有這麼個方法:
public boolean registerVIP(){
User user = new User();
user.type = "VIP";
return userDao.insertUser(user);
}
當咱們mock userDao的insertUser(user)方法時,咱們沒法肯定他的參數會是什麼樣子的,由於參數是咱們要測試的registerVIP這個方法new出來給他的,咱們能夠假定insertUser的方法邏輯的正確的,可是參數是registerVIP傳給他的,因此咱們得驗證參數的正確性。
public void testRegisterVIP(){
userDao = createMock(UserDao.class);
Capture<User> captureUser = new Capture<User>();
expect(userDao.insertUser(capture(captureUser))).andReturn(true).times(2);
replay(userDao);
userService.setUserDao(userDao);
userService.registerVIP();
assertEquals("VIP", captureUser.getValue().type); //驗證捕捉到的參數是否正確
assertEquals(true, userService.registerVIP());//驗證最後的結果
verify(userDao);
}
《對象重用》
爲了不生成過多的 Mock 對象,EasyMock 容許對原有 Mock 對象進行重用。要對 Mock 對象從新初始化,咱們能夠採用 reset 方法。和 replay 和 verify 方法相似,EasyMock 提供了兩種 reset 方式:(1)若是 Mock 對象是由 org.easymock.EasyMock 類中的靜態方法 createMock 生成的,那麼該 Mock 對象的能夠用 EasyMock 類的靜態方法 reset 從新初始化;(2)若是 Mock 方法是由 IMocksControl 實例的 createMock 方法生成的,那麼該 IMocksControl 實例方法 reset 的調用將會把全部該實例建立的 Mock 對象從新初始化。
在從新初始化以後,Mock 對象的狀態將被置爲 Record 狀態。
《多個mock 用 MocksControl》
當咱們須要mock一系列對象的時候,若是每一個都單獨去mock很麻煩, 這種狀況下能夠考慮使用MocksControl來簡化代碼:
IMocksControl mocksControl = createControl();
IMyInterface1 mock1 = mocksControl.createMock(IMyInterface1.class);
IMyInterface2 mock2 = mocksControl.createMock(IMyInterface2.class);
IMyInterface3 mock3 = mocksControl.createMock(IMyInterface3.class);
...
mocksControl.replay();
mocksControl.verify();
mocksControl.reset();
《Class mocking的限制》
1) 不能mock類的 final方法。若是final方法被調用,則只能執行原有的正常代碼。
2) 不能mock類的static 方法。
3) 一樣若是private方法被調用,只能執行原有的正常代碼。
4) 不能mock類的一些特殊方法: equals(), toString()和hashCode().緣由是easymock在實現是爲每一個class mock對象提供了內建的以上三個方法。須要強調的是,對於基於interface的mock,這個限制也是一樣存在的,即便以上三個方式是interface定義的一部分。
5) 在使用時須要避開這種場景,或者組合使用其餘的mock 框架好比jmockit來mock private方法和final方法。正則表達式