目录
什么是 Mock 测试?
1 如何使用Mockito?
2 实际使用
2.1 准备工作
2.2 开始测试
2.3 测试结果
3.几种Mock方式
3.1 借助Runwith
3.2 Annotation
3.3 借助Rule(不推荐)
3.4 Deepmock
参考
Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造出来)或者不容易获取比较复杂的对象(如 JDBC 中的ResultSet 对象),用一个虚拟的对象(Mock 对象)来创建以便测试的测试方法。
Mock 最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。
添加两段依赖
第一段依赖是单元测试框架JUnit ,关于JUnit框架可以参考:https://blog.csdn.net/qq_36110736/article/details/107774507
junit
junit
4.12
test
下面这部分就是Mockito的依赖
org.mockito
mockito-all
1.10.19
test
此处以一个Spring Boot 工程为测试工程,模拟一次用户登陆行为(只是简单的测试,所以整体逻辑并不完善)。
首先创建三个类 PO、DAO、Conreoller.
PO:其实是用不到其中的Setter/Getter 方法的。
package com.example.demo.po;
public class UserLogin {
private String userName;
private String passWord;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
}
DAO:直接抛出了异常,没有具体的实现
package com.example.demo.dao;
import com.example.demo.po.UserLoin;
public class LoginDao {
public UserLoin isExit(String username,String password){
throw new UnsupportedOperationException();
}
}
Controller:重写构造方法,将LoginDao 作为参数,实现了简单的逻辑:正常登陆,未找到用户,以及Dao层异常处理
package com.example.demo.controller;
import com.example.demo.dao.LoginDao;
import com.example.demo.po.UserLoin;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.http.HttpServletRequest;
public class LoginController {
private final LoginDao loginDao;
public LoginController(LoginDao loginDao) {
this.loginDao = loginDao;
}
public String Login(HttpServletRequest request){
final String userName = request.getParameter("username");
final String password = request.getParameter("password");
try {
UserLogin userLogin = loginDao.isExit(userName,password);
if (userLogin == null){
return "login";
}else {
return "index.jsp";
}
}catch (Exception e){
return "505";
}
}
}
大致流程:
package com.example.demo.controller;
import com.example.demo.dao.LoginDao;
import com.example.demo.po.UserLogin;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import javax.servlet.http.HttpServletRequest;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class LoginControllerTest {
private LoginDao loginDao;
private HttpServletRequest request;
private LoginController controller;
@Before
public void setUp() {
this.loginDao = Mockito.mock(LoginDao.class);
this.request = Mockito.mock(HttpServletRequest.class);
this.controller = new LoginController(loginDao);
}
@Test
public void testLoginFailure() {
when(request.getParameter("username")).thenReturn("bysen");
when(request.getParameter("password")).thenReturn("123456");
when(loginDao.isExit(anyString(),anyString())).thenReturn(null);
Assert.assertEquals("login",controller.Login(request));
}
@Test
public void testLoginSuccess(){
UserLogin login = new UserLogin();
when(request.getParameter("username")).thenReturn("bysen");
when(request.getParameter("password")).thenReturn("123456");
when(loginDao.isExit(anyString(),anyString())).thenReturn(login);
Assert.assertEquals("index.jsp",controller.Login(request));
}
@Test
public void testLogin505(){
when(request.getParameter("username")).thenReturn("bysen");
when(request.getParameter("password")).thenReturn("123456");
when(loginDao.isExit(anyString(),anyString())).thenThrow(UnsupportedOperationException.class);
Assert.assertEquals("505",controller.Login(request));
}
}
借助Junit的 @Runwith ,将参数设置为 MockitoJUnitRunner.class,例如:
package com.example.demo.test;
import com.example.demo.dao.LoginDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class MockitoRunnerTest {
@Test
public void test(){
LoginDao loginDao = mock(LoginDao.class);
loginDao.isExit(anyString(),anyString());
}
}
package com.example.demo.test;
import com.example.demo.dao.LoginDao;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.ArgumentMatchers.anyString;
public class MockByAnnotationTest {
@Mock(answer = Answers.RETURNS_SMART_NULLS)
private LoginDao loginDao;
@Before
public void before(){
MockitoAnnotations.initMocks(this);
}
@Test
public void test(){
loginDao.isExit(anyString(),anyString());
}
}
借助 MockitoJUnit.rule() 方法
package com.example.demo.test;
import com.example.demo.dao.LoginDao;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import static org.mockito.ArgumentMatchers.anyString;
public class MockByRuleTest {
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock
private LoginDao loginDao;
@Test
public void test(){
loginDao.isExit(anyString(),anyString());
}
}
一般来说,我们mock 出来的对象并不能完全代替原有的对象,在mock对象执行一些方法时很容易出现java.lang.NullPointerException,此时就需要Deepmock 来对特定操作返回特定值。
首先我们在Dao类中添加一个方法,返回一个空值。
public UserLogin getUser(){
return null;
}
然后:正常的mock对象,
package com.example.demo.test;
import com.example.demo.dao.LoginDao;
import com.example.demo.po.UserLogin;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
public class DeepMockTest {
@Mock
private LoginDao loginDao;
@Mock
private UserLogin user;
@Before
public void before(){
MockitoAnnotations.initMocks(this);
}
@Test
public void test(){
// Mockito.when(loginDao.getUser()).thenReturn(user);
UserLogin userLogin = loginDao.getUser();
System.out.println("=======");
System.out.println(userLogin);
System.out.println("=======");
}
}
如果不使用 when().thenReturn()的话,结果为null。
使用的话:
https://www.cnblogs.com/bodhitree/p/9456515.html
https://www.bilibili.com/video/BV1jJ411A7Sv