一、Mockito的使用场景
在写test case的时候, 我们不应该有任何的外部的依赖,比如:
- 需要访问数据库拿数据或者更新数据
- 不应该依赖网络去下载文件
- 发送mail的时候,不应该依赖任何SMTP server
。。。
Mock就是做一个假的object,对这个object里的方法的调用,都会被已经Mock的假对象拦截,然后返回用户预设的行为。这样可以绕过需要从其它地方拿数据的地方,直接返回用户预设的数据,进行单元测试。
最常用的mock框架就是mockito、PowerMock。一般用mockito。
PowerMock:是在EasyMock 以及 Mockito上的扩展,可以实现对静态函数、构造函数、私有函数、Final 函数以及系统函数的模拟
二、Mockito的pom依赖
<!-- https://mvnrepository.com/artifact/junit/junit -->
<!-- 要用junit4 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.3.3</version>
<scope>test</scope>
</dependency>
三、3中Mock方式
//1. 用@RunWith指定runner, 推荐
@RunWith(MockitoJUnitRunner.class)
public class AccountControllerTestAnnation {
}
//2. 在Before中调用initMocks方法
public class AccountControllerTestAnnation {
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}
}
//3.MockitoJUnit.rule()
public class AccountControllerTestAnnation {
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
}
四、Mocktio简单例子
注解方式mock,推荐
import com.springboot.dao.AccountDao;
import com.springboot.entiry.Account;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import javax.servlet.http.HttpServletRequest;
import static org.mockito.ArgumentMatchers.anyString;
@RunWith(MockitoJUnitRunner.class)
public class AccountControllerTestAnnation {
//@InjectMocks标注在被测试类上,@Mock的对象会自动注入该类中,比如AccountController用到AccountDao。 那么在Mock AccountDao的时候,AccountController里的AccountDao也会被设置
@InjectMocks
AccountController accountController;
@Mock
HttpServletRequest request;
//@Mock的对象会返回一个没有set任何值的对象。就相当与new AccountDao()
@Mock
AccountDao accountDao;
@Test
public void login_success() throws Exception {
Account account = new Account();
//subbing,对request.getParameter()进行mock,当调用request.getParameter("userName")时,会被mock截取并返回"Vivienne"
Mockito.when(request.getParameter("userName")).thenReturn("Vivienne");
Mockito.when(request.getParameter("password")).thenReturn("123");
//subbing,对accountDao.findAccount()进行mock,anyString()表示无论传入的参数是什么,都会被mock截取并返回account
Mockito.when(accountDao.findAccount(anyString(), anyString())).thenReturn(account);
//断言,判断结果,如果返回"/index",则测试通过
Assert.assertEquals("/index",accountController.login(request));
}
}
public class AccountController {
@Autowired
AccountDao accountDao;
@RequestMapping
public String login(HttpServletRequest request){
try {
String userName = request.getParameter("userName");
String password = request.getParameter("password");
Account account = accountDao.findAccount(userName, password);
if(account==null){
return "/login";
}else{
return "/index";
}
} catch (Exception e) {
System.out.println(e.getMessage());
return "/505";
}
}
}
public class AccountDao {
public Account findAccount(String userName, String password) throws Exception {
throw new Exception("DB could not use now"); //模拟DB不可用
}
}
public class Account {
private String userName;
private String password;
...
以下时采用非注解的方式mock
@RunWith(MockitoJUnitRunner.class)
public class AccountControllerTestNonAnnation {
//不用@Mock
private AccountController accountController;
private HttpServletRequest request;
private AccountDao accountDao;
@Before
public void setup() throws NoSuchFieldException, IllegalAccessException {
this.request = Mockito.mock(HttpServletRequest.class);
this.accountDao = Mockito.mock(AccountDao.class);
this.accountController = new AccountController();
Field ad = accountController.getClass().getDeclaredField("accountDao");
ad.setAccessible(true);
ad.set(accountController, accountDao);
}
@Test
public void login_success() throws Exception {
Account account = new Account();
Mockito.when(request.getParameter("userName")).thenReturn("Vivienne");
Mockito.when(request.getParameter("password")).thenReturn("123");
Mockito.when(accountDao.findAccount(anyString(), anyString())).thenReturn(account);
Assert.assertEquals("/index", accountController.login(request));
}
}
五、关于深度Mock(Deep Mock)
以下两种方式是一样的,但是如果程序运行时如果需要对结果进行subbing,就不能用deep mock
@RunWith(MockitoJUnitRunner.class)
public class AccountControllerTestDeepMock {
//自动mock程序运行所需对象,这里自动mock了dog
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
Person person;
@Test
public void testDeepMockDog() throws Exception {
Dog dog = person.getDog();
dog.getDogName();
}
}
@RunWith(MockitoJUnitRunner.class)
public class AccountControllerTestDeepMock {
@Mock
Person person;
//手动mock了程序运行时所需对象dog
@Mock
Dog dog;
@Test
public void testDeepMockDog() throws Exception {
Mockito.when(person.getDog()).thenReturn(dog);
Dog dog = person.getDog();
dog.getDogName();
}
}
entity
public class Dog {
private String dogName;
public String getDogName() {
return "dog";
}
public void setDogName(String dogName) {
this.dogName = dogName;
}
}
public class Person {
private String name;
private Dog dog;
public Dog getDog() {
return dog;
}
...set/get...
关于Subbing、Assert、Spy、Matcher等其他具体详解,请参考另一半文章。
转载:https://blog.csdn.net/Vivienne_ChenW/article/details/105469432
查看评论