单元测试框架——Mockito

目录

什么是 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 测试?

        Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造出来)或者不容易获取比较复杂的对象(如 JDBC 中的ResultSet 对象),用一个虚拟的对象(Mock 对象)来创建以便测试的测试方法。

        Mock 最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。

1 如何使用Mockito?

添加两段依赖

        第一段依赖是单元测试框架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

2 实际使用

        此处以一个Spring Boot 工程为测试工程,模拟一次用户登陆行为(只是简单的测试,所以整体逻辑并不完善)。

2.1 准备工作

       首先创建三个类 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";
        }

    }
}

2.2 开始测试

大致流程:

  1. 修改 @RunWith()MockitoJUnitRunner.class
  2. 添加三个会用到属性
  3. 在  @Before 修饰的方法中 使用 mock 进行初始化
  4. 分别创建三个方法对三种情况(未找到用户、正常登陆、异常)进行测试
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));
    }
}

2.3 测试结果

单元测试框架——Mockito_第1张图片

3.几种Mock方式

3.1 借助Runwith

        借助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());
    }
}

3.2 Annotation

  •        在测试类中创建一个用 @Before 修饰的方法,
  •        在其中添加 MockitoAnnotations.initMocks(this)
  •        就可以直接使用@Mock注解mock对象。
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());
    }
}

3.3 借助Rule(不推荐)

       借助 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());
    }
}

3.4 Deepmock

        一般来说,我们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。

单元测试框架——Mockito_第2张图片

使用的话:

单元测试框架——Mockito_第3张图片

参考

https://www.cnblogs.com/bodhitree/p/9456515.html

https://www.bilibili.com/video/BV1jJ411A7Sv

你可能感兴趣的:(单元测试框架——Mockito)