IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> Mockito 实战总结笔记 -> 正文阅读

[开发测试]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;

	// 每次测试开始前都会调用该方法,初始化上面定义的变量
    @Before
    public void setUp() {
        this.accountDao = Mockito.mock(AccountDao.class); // 创建一个AccountDao的“替身”
        this.request = Mockito.mock(HttpServletRequest.class); // 创建一个HttpServletRequest的“替身”
        this.accountLoginController = new AccountLoginController(accountDao);
    }

	// 测试返回"/index"的情况
    @Test
    public 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"的情况
    @Test
    public 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"的情况
    @Test
    public 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 {

    @Test
    public 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 {

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Mock
    private AccountDao accountDao;

    @Test
    public 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 {

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }
    
    @Mock(answer = Answers.RETURNS_SMART_NULLS)
    private AccountDao accountDao;

    @Test
    public 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 {

    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Test
    public 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 {

    @Mock
    private PersonService personService;

    @Mock
    private Person person;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public 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 {

    @Mock
    private PersonService personService;

    @Mock
    private Person person;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testDeepMock() {
        Person person = personService.get();
        person.foo(); // 此时会报空指针异常
    }

	@Test
	public 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 Mock
    private PersonService personService;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testDeepMock() {
        personService.get().foo();
    }

}

Mockito Stubbing 语法详解

#未完待续

参考教程:汪文君Mockito实战视频

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:53:03  更:2022-03-24 00:53:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/18 0:46:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码