mock測試就是在測試過程中,對於某些不容易構造或者不容易獲取的對象,用一個虛擬的對象來創建以便測試的測試方法。這個虛擬的對象就是mock對象。mock對象就是真實對象在調試期間的代替品。
使用mock對象測試的關鍵步驟:使用一個接口來描述這個對象 在產品代碼中實現這個接口 在測試代碼中實現這個接口 在被測試代碼中只是通過接口來引用對象,所以它不知道這個引用的對象是真實對象。還是mock對象。
使用Mock Object進行測試,主要是用來模擬那些在應用中不容易構造(如HttpServletRequest必須在Servlet容器中才能構造出來)或者比較複雜的對象(如JDBC中的ResultSet對象)從而使測試順利進行的工具。
目前,在Java陣營中主要的Mock測試工具有JMock,MockCreator,Mockrunner,EasyMock,MockMaker等
如果UserService開發完畢,但UserDao尚未開發或未開發完畢,這時又想測試UserService,那麼就可以通過Mock方式來測試。用EasyMock虛擬一個UserDao對象,然後在虛擬的UserDao上針對UserService方法所需的各方法進行聲明其可能出現的調用結果,也就是聲明UserDao各方法所需的傳入參數和返回結果,最後再調用UserService中的方法(即內部調用了UserDao的方法)並驗證返回結果。
如果對UserService方法的Mock測試全部通過,則表明UserService是編寫正確的
說白了,當我們發現所依賴的對象沒有實現,而此時又想做測試的話,就可以考慮用Mock來做測試
Mock創建方式
createMock-------->此時創建的mock對象在進行verify時僅僅檢查關聯方法是否正常完成調用,只要完成次數一致就認爲測試通過
createNiceMock---->很少使用,略掉
createStrictMock-->與createMock不同的是,它還要驗證關聯方法的調用順序,即verify時要同時驗證完成調用的次數和調用順序
public class UserServiceTest {
@Test
public void testMock(){
//創建DAO的Mock對象
UserDao dao = EasyMock.createMock(UserDao.class);
//進入record階段:當調用dao.load()方法且傳入參數爲Jadyer時,其返回值爲user對象
User user = new User(2,"Jadyer", "hongyu");
//如果UserService.get()裏面調用了兩次dao.load(),那麼這裏就要指定其次數
//EasyMock.expect(dao.load("Jadyer")).andReturn(user).times(2);
EasyMock.expect(dao.load("Jadyer")).andReturn(user);
//進入replay階段
EasyMock.replay(dao);
UserService service = newUserServiceImpl(dao);
User user22 =service.get("Jadyer");
Assert.assertNotNull(user22);
Assert.assertEquals(user22.getId(),user.getId());
Assert.assertEquals(user22.getUsername(), user.getUsername());
Assert.assertEquals(user22.getPassword(), user.getPassword());
//進入verify階段
EasyMock.verify(dao);
}
/**
*測試StrictMock的使用
*/
@Test
public void testStrictMock(){
UserDao dao =EasyMock.createStrictMock(UserDao.class);
User user = new User(2,"Jadyer", "hongyu");
//關鍵在這裏:必須把交互的所有過程都記錄下來,也就是說dao方法被調用了幾次,分別是調用的哪個方法,包括傳的參數及返回值
//若UserServiceImpl.getTwice()中調用兩次load()傳入參數都是Jadyer,那麼下面這兩次的expect()操作便可寫成一行
//EasyMock.expect(dao.load("Jadyer")).andReturn(user).times(2);
EasyMock.expect(dao.load("jadyer")).andReturn(user);
//expectLastCall()是用來操作沒有返回值的方法,此時要先執行dao中沒有返回值的方法,然後再調用expectLastCall()方法
dao.delete("Jadyer");
EasyMock.expectLastCall();
EasyMock.expect(dao.load("Jadyer")).andReturn(user);
EasyMock.replay(dao);
UserService service = newUserServiceImpl(dao);
User user22 =service.list("Jadyer");
Assert.assertNotNull(user22);
Assert.assertEquals(user22.getId(),user.getId());
Assert.assertEquals(user22.getUsername(), user.getUsername());
Assert.assertEquals(user22.getPassword(), user.getPassword());
EasyMock.verify(dao);
}
/**
*使用MocksControl可以檢查一組調用對象之間的關係
*它比較適用於這種情景-->UserService中的某個方法依賴於UserDao和BlogDao等多個對象的情況
*/
@Test
public void testMocksControl(){
//也可以通過Control創建一組Mock對象,如EasyMock.createControl()
IMocksControl control =EasyMock.createStrictControl();
//這時創建的Mock對象就類似於EasyMock.createStrictMock(UserDao.class);
UserDao userDao =control.createMock(UserDao.class);
BlogDao blogDao =control.createMock(BlogDao.class);
blogDao.update("Jadyer");
EasyMock.expectLastCall();
userDao.delete("Jadyer");
EasyMock.expectLastCall();
//讓MocksControl進行操作
control.replay();
new UserServiceImpl(userDao,blogDao).update("Jadyer");
//驗證MocksControl中的所有mock調用
control.verify();
}
/**
*測試添加一個不存在的用戶
*/
@Test
public void testInsertNotExistUser(){
//先做好準備工作
UserDao dao =EasyMock.createStrictMock(UserDao.class);
User user = new User(2,"Jadyer", "hongyu");
UserService service = newUserServiceImpl(dao);
//然後開始EasyMock的測試(先要保證用戶不存在,所以要先andReturn(null))
EasyMock.expect(dao.load(user.getUsername())).andReturn(null);
EasyMock.expect(dao.save(user)).andReturn(user);
EasyMock.replay(dao);
User user22 =service.insert(user);
Assert.assertNotNull(user22);
Assert.assertEquals(user22.getId(),user.getId());
Assert.assertEquals(user22.getUsername(), user.getUsername());
Assert.assertEquals(user22.getPassword(), user.getPassword());
EasyMock.verify(dao);
}
/**
*測試添加一個存在的用戶
* @see爲了查看效果,可以將expected=RuntimeException.class刪去
*/
@Test(expected=RuntimeException.class)
public void testInsertExistUser(){
//先做好準備工作
UserDao dao =EasyMock.createStrictMock(UserDao.class);
User user = new User(2,"Jadyer", "hongyu");
UserService service = newUserServiceImpl(dao);
//然後開始EasyMock的測試(先要保證用戶存在,所以要先andReturn(user))
EasyMock.expect(dao.load(user.getUsername())).andReturn(user);
EasyMock.expect(dao.save(user)).andReturn(user);
EasyMock.replay(dao);
User user22 =service.insert(user);
Assert.assertNotNull(user22);
Assert.assertEquals(user22.getId(),user.getId());
Assert.assertEquals(user22.getUsername(), user.getUsername());
Assert.assertEquals(user22.getPassword(), user.getPassword());
EasyMock.verify(dao);
}
/**
*測試用戶登錄成功
*/
@Test
public void testLoginSuccess(){
//同樣先做好準備工作
UserDao dao =EasyMock.createStrictMock(UserDao.class);
User user = new User(2,"Jadyer", "hongyu");
UserService service = newUserServiceImpl(dao);
//開始測試
//指定測試時所要登錄的用戶名和密碼,由於這裏是要測試登錄成功的情況,所以這裏用戶名密碼就要與準備數據中的相同
String username ="Jadyer";
String password ="hongyu";
//先要保證用戶存在,所以要先andReturn(user)
EasyMock.expect(dao.load(username)).andReturn(user);
EasyMock.replay(dao);
User user22 =service.login(username, password);
Assert.assertNotNull(user22);
Assert.assertEquals(user22.getId(),user.getId());
Assert.assertEquals(user22.getUsername(),user.getUsername());
Assert.assertEquals(user22.getPassword(), user.getPassword());
EasyMock.verify(dao);
}
/**
*測試用戶登錄失敗(用戶不存在)
* @see爲了查看效果,可以將expected=RuntimeException.class刪去
*/
@Test(expected=RuntimeException.class)
public void testLoginFailNotExistUser(){
//同樣先做好準備工作
UserDao dao =EasyMock.createStrictMock(UserDao.class);
UserService service = newUserServiceImpl(dao);
//開始測試
//指定測試時所要登錄的是一個不存在的用戶
String username ="Jaders";
String password ="hongyu";
//爲了保證用戶存在,這裏就要andReturn(null),因爲dao.load一個不存在用戶時取到的是null
EasyMock.expect(dao.load(username)).andReturn(null);
EasyMock.replay(dao);
service.login(username,password);
EasyMock.verify(dao);
}
/**
*測試用戶登錄失敗(用戶密碼錯誤)
* @see爲了查看效果,可以將expected=RuntimeException.class刪去
*/
@Test(expected=RuntimeException.class)
public void testLoginFailPasswordError(){
//同樣先做好準備工作
UserDao dao =EasyMock.createStrictMock(UserDao.class);
User user = new User(2,"Jadyer", "hongyu");
UserService service = newUserServiceImpl(dao);
//開始測試
//指定測試時所要登錄的是一個密碼錯誤的用戶
String username ="Jadyer";
String password ="xuanyu";
//密碼錯誤時用戶是存在的,所以要andReturn(user)
EasyMock.expect(dao.load(username)).andReturn(user);
EasyMock.replay(dao);
service.login(username,password);
EasyMock.verify(dao);
}
}