Mockito的简单用法示例

2024-05-23 07:08
文章标签 简单 用法 示例 mockito

本文主要是介绍Mockito的简单用法示例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Mockito是一个流行的Mocking框架。它使用起来简单,学习成本很低,而且具有非常简洁的API,测试代码的可读性很高。因此它十分受欢迎,用 户群越来越多,很多的开源的软件也选择了Mockito。要想了解更多有关Mockito的信息,请访问它的官方网 站:http://mockito.org/

一、简单示例

/** Creation : 2015年8月14日*/
package com.tan.test;import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;import java.util.Iterator;
import java.util.List;
import java.util.Map;import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;import edu.emory.mathcs.backport.java.util.LinkedList;public class MockitoTest {/*** 通过when(mock.someMethod()).thenReturn(value) 来设定mock对象某个方法调用时的返回值*/@Testpublic void simpleTest() {// arrangeIterator i = mock(Iterator.class);when(i.next()).thenReturn("Hello").thenReturn("World");// actString result = i.next() + " " + i.next();// 验证i.next()是否被调用了2次,不关心返回值verify(i, times(2)).next();// 断言结果是否和预期一样assertEquals("Hello World", result);}/*** 参数匹配器--Argument matchers test.*/@Testpublic void argumentMatchersTest() {List<String> mock = mock(List.class);// anyInt()参数匹配器来匹配任何的int 类型的参数when(mock.get(anyInt())).thenReturn("Hello").thenReturn("World");// 所以当第一次调用get方法时输入任意参数为100方法返回”Hello”,第二次调用时输入任意参数200返回值”World”。String result = mock.get(100) + " " + mock.get(200);// verfiy 验证的时候也可将参数指定为anyInt()匹配器,那么它将不关心调用时输入的参数的具体参数值。verify(mock, times(2)).get(anyInt());assertEquals("Hello World", result);/* 注意:如果使用了参数匹配器,那么所有的参数需要由匹配器来提供,否则将会报错。 */}/*** 参数匹配器--Argument matchers test2.*/@SuppressWarnings("unchecked")@Testpublic void argumentMatchersTest2() {Map<Integer, String> mapMock = mock(Map.class);when(mapMock.put(anyInt(), anyString())).thenReturn("world");mapMock.put(1, "hello");// 注:在最后的验证时如果只输入字符串”hello”是会报错的,必须使用Matchers 类内建的eq方法。// 如果将anyInt()换成1进行验证也需要用eq(1)。verify(mapMock).put(anyInt(), eq("hello"));}/*** 3.Mock对象的行为验证--Verify test.*/@Testpublic void verifyTest() {List<String> mock = mock(List.class);List<String> mock1 = mock(List.class);when(mock.get(0)).thenReturn("hello");mock.get(0);mock.get(1);mock.get(2);mock1.get(0);/* 方法的调用不关心是否模拟了get(2)方法的返回值,只关心mock 对象后,是否执行了mock.get(2),如果没有执行,测试方法将不会通过。 */verify(mock).get(2); // 验证对象mock是否调用了get(2)方法verify(mock, never()).get(3); // 方法中可以传入never()方法参数来确认mock.get(3)方法不曾被执行过/* 确认mock1对象没有进行任何交互===>测试不通过 */verifyNoMoreInteractions(mock1); // 将其放在 mock1.get(0);之前即可通过。}/*** 验证方法的调用顺序.*/@Testpublic void testInvokeOrder() {List<String> firstMock = mock(List.class);List<String> secondMock = mock(List.class);firstMock.add("was called first");firstMock.add("was called first");secondMock.add("was called second");secondMock.add("was called third");/* 如果mock方法的调用顺序和InOrder中verify的顺序不同,那么测试将执行失败。 */InOrder inOrder = inOrder(secondMock, firstMock);inOrder.verify(firstMock, times(2)).add("was called first");inOrder.verify(secondMock).add("was called second");// 因为在secondMock.add("was called third")之后已经没有多余的方法调用了。inOrder.verify(secondMock).add("was called third");inOrder.verifyNoMoreInteractions();// 表示此方法调用后再没有多余的交互}/*** 自定义Answer接口(方法预期回调接口)的应用*/@Testpublic void customAnswerTest() {List<String> mock = mock(List.class);when(mock.get(4)).thenAnswer(new Answer() {public String answer(InvocationOnMock invocation) throws Throwable {Object[] args = invocation.getArguments();Integer num = (Integer) args[0];if (num > 3) {return "yes";}throw new RuntimeException();}});System.out.println(mock.get(4));}/*** 利用ArgumentCaptor(参数捕获器)捕获方法参数进行验证*/@Testpublic void argumentCaptorTest() {List mock = mock(List.class);List mock2 = mock(List.class);mock.add("John");mock2.add("Brian");mock2.add("Jim");/** 首先构建ArgumentCaptor需要传入捕获参数的对象,例子中是String。接着要在 verify 方法的参数中调用argument.capture()方法来捕获输入的参数, <br> 之后* argument变量中就保存了参数值,可以用argument.getValue()获取。*/ArgumentCaptor argument = ArgumentCaptor.forClass(String.class);verify(mock).add(argument.capture());assertEquals("John", argument.getValue());verify(mock2, times(2)).add(argument.capture());assertEquals("Jim", argument.getValue());/* argument.getAllValues(),它将返回参数值的List。 */assertArrayEquals(new Object[] { "John", "Brian", "Jim" }, argument.getAllValues().toArray());}/*** Spy-对象的监视<br>* Mock 对象只能调用stubbed 方法,调用不了它真实的方法。但Mockito 可以监视一个真实的对象,这时对它进行方法调用时它将调用真实的方法,<br>* 同时也可以stubbing 这个对象的方法让它返回我们的期望值。另外不论是否是真实的方法调用都可以进行verify验证。<br>* 和创建mock对象一样,对于final类、匿名类和Java的基本类型是无法进行spy的。*/@Testpublic void spyTest2() {List list = new LinkedList();List spy = spy(list);// optionally, you can stub out some methods:when(spy.size()).thenReturn(100);// using the spy calls real methodsspy.add("one");spy.add("two");// prints "one" - the first element of a listSystem.out.println(spy.get(0));// size() method was stubbed - 100 is printedSystem.out.println(spy.size());// optionally, you can verifyverify(spy).add("one");verify(spy).add("two");}}


二、注解用法
Mockito对Annotation的支持
Mockito 支持对变量进行注解,例如将mock 对象设为测试类的属性,然后通过注解的方式@Mock 来定义它,这样有利于减少重复代码,增强可读性,易于排查错误等。除了支持@Mock,Mockito支持的注解还有@Spy(监视真实的对象),@Captor(参数捕获器),@InjectMocks(mock对象自动注入)。
Annotation的初始化只有Annotation还不够,要让它们工作起来还需要进行初始化工作。初始化的方
法为:MockitoAnnotations.initMocks(testClass)参数testClass是你所写的测试类。一般情况下在Junit4的@Before 定义的方法中执行初始化工作,如下:

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

除了上述的初始化的方法外,还可以使用Mockito 提供的Junit Runner:
MockitoJUnitRunner这样就省略了上面的步骤。

@RunWith(MockitoJUnit44Runner.class)
public class ExampleTest {
...
}

@Mock 注解
使用@Mock注解来定义mock对象有如下的优点:
1. 方便mock对象的创建
2. 减少mock对象创建的重复代码
3. 提高测试代码可读性
4. 变量名字作为mock对象的标示,所以易于排错
@Mock注解也支持自定义name 和answer属性。下面是官方给出的@Mock使用的例子:

public class ArticleManagerTest extends SampleBaseTestCase {
@Mock
private ArticleCalculator calculator;
@Mock(name = "dbMock")
private ArticleDatabase database;
@Mock(answer = RETURNS_MOCKS)
private UserProvider userProvider;
private ArticleManager manager;
@Before
public void setup() {
manager = new ArticleManager(userProvider, database,
calculator);
}
}
public class SampleBaseTestCase {
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
}

@Spy 注解
Spy的使用方法请参阅前面的章节,在此不再赘述,下面是使用方法:

public class Test{
@Spy
Foo spyOnFoo = new Foo();
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}
...
}

@Captor 注解
@Captor是参数捕获器的注解,有关用法见前章,通过注解的方式也可以更便捷
的对它进行定义。使用例子如下:

public class Test {
@Captor
ArgumentCaptor<AsyncCallback<Foo>> captor;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
public void shouldDoSomethingUseful() {
// ...
verify(mock.doStuff(captor.capture()));
assertEquals("foo", captor.getValue());
}
}

@InjectMocks 注解
通过这个注解,可实现自动注入mock 对象。当前版本只支持setter 的方式进行
注入,Mockito 首先尝试类型注入,如果有多个类型相同的mock 对象,那么它
会根据名称进行注入。当注入失败的时候Mockito不会抛出任何异常,所以你可
能需要手动去验证它的安全性。
例:

@RunWith(MockitoJUnit44Runner.class)
public class ArticleManagerTest {
@Mock
private ArticleCalculator calculator;
@Mock
private ArticleDatabase database;
@Spy
private UserProvider userProvider = new ConsumerUserProvider();
@InjectMocks
private ArticleManager manager = new ArticleManager();
@Test
public void shouldDoSomething() {
manager.initiateArticle();
verify(database).addListener(any(ArticleListener.class));
}
}

上例中, ArticleDatabase 是ArticleManager 的一个属性, 由于
ArticleManager 是注解@InjectMocks 标注的,所以会根据类型自动调用它的
setter方法为它设置ArticleDatabase

这篇关于Mockito的简单用法示例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/996169

相关文章

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(

Golang使用etcd构建分布式锁的示例分享

《Golang使用etcd构建分布式锁的示例分享》在本教程中,我们将学习如何使用Go和etcd构建分布式锁系统,分布式锁系统对于管理对分布式系统中共享资源的并发访问至关重要,它有助于维护一致性,防止竞... 目录引言环境准备新建Go项目实现加锁和解锁功能测试分布式锁重构实现失败重试总结引言我们将使用Go作

JAVA利用顺序表实现“杨辉三角”的思路及代码示例

《JAVA利用顺序表实现“杨辉三角”的思路及代码示例》杨辉三角形是中国古代数学的杰出研究成果之一,是我国北宋数学家贾宪于1050年首先发现并使用的,:本文主要介绍JAVA利用顺序表实现杨辉三角的思... 目录一:“杨辉三角”题目链接二:题解代码:三:题解思路:总结一:“杨辉三角”题目链接题目链接:点击这里

SpringBoot使用注解集成Redis缓存的示例代码

《SpringBoot使用注解集成Redis缓存的示例代码》:本文主要介绍在SpringBoot中使用注解集成Redis缓存的步骤,包括添加依赖、创建相关配置类、需要缓存数据的类(Tes... 目录一、创建 Caching 配置类二、创建需要缓存数据的类三、测试方法Spring Boot 熟悉后,集成一个外

Springboot使用RabbitMQ实现关闭超时订单(示例详解)

《Springboot使用RabbitMQ实现关闭超时订单(示例详解)》介绍了如何在SpringBoot项目中使用RabbitMQ实现订单的延时处理和超时关闭,通过配置RabbitMQ的交换机、队列和... 目录1.maven中引入rabbitmq的依赖:2.application.yml中进行rabbit

Python绘制土地利用和土地覆盖类型图示例详解

《Python绘制土地利用和土地覆盖类型图示例详解》本文介绍了如何使用Python绘制土地利用和土地覆盖类型图,并提供了详细的代码示例,通过安装所需的库,准备地理数据,使用geopandas和matp... 目录一、所需库的安装二、数据准备三、绘制土地利用和土地覆盖类型图四、代码解释五、其他可视化形式1.

opencv实现像素统计的示例代码

《opencv实现像素统计的示例代码》本文介绍了OpenCV中统计图像像素信息的常用方法和函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 统计像素值的基本信息2. 统计像素值的直方图3. 统计像素值的总和4. 统计非零像素的数量

Python使用asyncio实现异步操作的示例

《Python使用asyncio实现异步操作的示例》本文主要介绍了Python使用asyncio实现异步操作的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录1. 基础概念2. 实现异步 I/O 的步骤2.1 定义异步函数2.2 使用 await 等待异