小言_互联网的博客

Mockito详解(一)介绍及例子

329人阅读  评论(0)

Mockito官网

一、Mockito的使用场景

在写test case的时候, 我们不应该有任何的外部的依赖,比如:

  1. 需要访问数据库拿数据或者更新数据
  2. 不应该依赖网络去下载文件
  3. 发送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等其他具体详解,请参考另一半文章。

Mockito详解(二)Mockito中的语法和示例


转载:https://blog.csdn.net/Vivienne_ChenW/article/details/105469432
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场