Mockito 实战总结笔记
其他 mock 框架:powermock、easymock、jmock
mockito 官網:https://site.mockito.org
mockito 是一個單元測試框架。
Mockito 快速入門
下面來演示 Mockito 的入門案例。
包結構如下:
代碼如下:
實體類 Account.java:
public class Account { }dao 層 AccountDao.java,該類中有一個接口,并且模擬數據庫宕機的情況:
public class AccountDao {public Account findAccount(String username, String password) {throw new UnsupportedOperationException(); // 模擬數據庫宕機情況}}controller 層 AccountLoginController.java,該類中有一個接口:
public class AccountLoginController {private final AccountDao accountDao;public AccountLoginController(AccountDao accountDao) {this.accountDao = accountDao;}public String login(HttpServletRequest request) {final String userName = request.getParameter("username");final String password = request.getParameter("password");try {Account account = accountDao.findAccount(userName, password);if (account == null) {return "/login"; // 模擬返回登錄頁面} else {return "/index"; // 模擬登錄成功}} catch (Exception e) {return "/505"; // 模擬出錯情況}}}此時 controller 層的接口 login() 已經定義好了,現在要對其進行單元測試,但沒有此時這個程序的環境中沒有 servlet 容器,也沒有數據庫,如何進行測試?用 mockito !
AccountLoginControllerTest.java:
import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner;import javax.servlet.http.HttpServletRequest;import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.when;@RunWith(MockitoJUnitRunner.class) // 使用mockito進行單元測試,記得加上這個注解 public class AccountLoginControllerTest {private AccountDao accountDao;private HttpServletRequest request;private AccountLoginController accountLoginController;// 每次測試開始前都會調用該方法,初始化上面定義的變量@Beforepublic void setUp() {this.accountDao = Mockito.mock(AccountDao.class); // 創建一個AccountDao的“替身”this.request = Mockito.mock(HttpServletRequest.class); // 創建一個HttpServletRequest的“替身”this.accountLoginController = new AccountLoginController(accountDao);}// 測試返回"/index"的情況@Testpublic void testLoginSuccess() {Account account = new Account();// 意思是:當調用request.getParameter("username")時,讓request.getParameter("username")返回"john"when(request.getParameter("username")).thenReturn("john"); when(request.getParameter("password")).thenReturn("123456");// anyString():任意字符串when(accountDao.findAccount(anyString(), anyString())).thenReturn(account);// 通過斷言來驗證結果assertThat(accountLoginController.login(request), equalTo("/index"));}// 測試返回"/login"的情況@Testpublic void testLoginFailure() {when(request.getParameter("username")).thenReturn("john");when(request.getParameter("password")).thenReturn("123456");when(accountDao.findAccount(anyString(), anyString())).thenReturn(null);assertThat(accountLoginController.login(request), equalTo("/login"));}// 測試返回"/505"的情況@Testpublic void testLogin505() {when(request.getParameter("username")).thenReturn("john");when(request.getParameter("password")).thenReturn("123456");when(accountDao.findAccount(anyString(), anyString())).thenThrow(UnsupportedOperationException.class); // 注意這調的是thenThrow()assertThat(accountLoginController.login(request), equalTo("/505"));}}三種不同的 mock 方式
方式一:使用 @RunWith 注解
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner;import static org.mockito.Mockito.mock;@RunWith(MockitoJUnitRunner.class) public class MockByRunnerTest {@Testpublic void testMock() {AccountDao accountDao = mock(AccountDao.class);Account account = accountDao.findAccount("x", "x");System.out.println(account);}}打印結果:
null如果不希望 account 為 null,可以將代碼修改如下:
@Test public void testMock() {AccountDao accountDao = mock(AccountDao.class, Mockito.RETURNS_SMART_NULLS);Account account = accountDao.findAccount("x", "x");System.out.println(account); }此時打印結果:
SmartNull returned by this unstubbed method call on a mock: accountDao.findAccount("x", "x");方式二:@Mock 注解
import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations;public class MockByAnnotationTest {@Beforepublic void init() {MockitoAnnotations.initMocks(this);}@Mockprivate AccountDao accountDao;@Testpublic void testMock() {Account account = accountDao.findAccount("x", "x");System.out.println(account);}}打印結果:
null同樣,若不想 account 為 null,可按如下編碼:
import org.junit.Before; import org.junit.Test; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations;public class MockByAnnotationTest {@Beforepublic void init() {MockitoAnnotations.initMocks(this);}@Mock(answer = Answers.RETURNS_SMART_NULLS)private AccountDao accountDao;@Testpublic void testMock() {Account account = accountDao.findAccount("x", "x");System.out.println(account);}}打印結果:
SmartNull returned by this unstubbed method call on a mock: accountDao.findAccount("x", "x");方式三:@Rule 注解
import org.junit.Rule; import org.junit.Test; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule;import static org.mockito.Mockito.mock;public class MockByRuleTest {@Rulepublic MockitoRule mockitoRule = MockitoJUnit.rule();@Testpublic void testMock() {AccountDao accountDao = mock(AccountDao.class);Account account = accountDao.findAccount("x", "x");System.out.println(account);}}打印結果:
null深度 Mock(Deep Mock)
下面的例子中使用 @Mock 注解來進行單元測試:
import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations;import static org.mockito.Mockito.when;public class DeepMockTest {@Mockprivate PersonService personService;@Mockprivate Person person;@Beforepublic void init() {MockitoAnnotations.initMocks(this);}@Testpublic void testDeepMock() {Person person = personService.get();person.foo(); // 此時會報空指針異常}}此時 testDeepMock() 測試無法通過,會報空指針異常,因為 person 為 null。
為了改進這個問題,將單元測試定義如下:
@Test public void testDeepMock2() {when(personService.get()).thenReturn(person);Person person = personService.get();person.foo(); }此時可以通過測試,完整代碼如下:
import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations;import static org.mockito.Mockito.when;public class DeepMockTest {@Mockprivate PersonService personService;@Mockprivate Person person;@Beforepublic void init() {MockitoAnnotations.initMocks(this);}@Testpublic void testDeepMock() {Person person = personService.get();person.foo(); // 此時會報空指針異常}@Testpublic void testDeepMock2() {when(personService.get()).thenReturn(person);Person person = personService.get();person.foo();}}對于上面代碼,可以通過 Deep Mock 方式進行代碼簡化。簡化后的代碼如下:
import org.junit.Before; import org.junit.Test; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations;public class DeepMockTest {@Mock(answer = Answers.RETURNS_DEEP_STUBS) // 指定為Deep Mockprivate PersonService personService;@Beforepublic void init() {MockitoAnnotations.initMocks(this);}@Testpublic void testDeepMock() {personService.get().foo();}}Mockito Stubbing 語法詳解
#未完待續
參考教程:汪文君Mockito實戰視頻
總結
以上是生活随笔為你收集整理的Mockito 实战总结笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQA
- 下一篇: MongoDB的安装与使用