`
qiuguo0205
  • 浏览: 242486 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

使用Mockito进行单元测试【1】——mock and verify

 
阅读更多

1. 为什么使用Mockito来进行单元测试?

 

回答这个问题需要回答两个方面,第一个是为什么使用mock?mock其实是一种工具的简称,他最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。

 

比如一段代码有这样的依赖:

 

 

当我们需要测试A类的时候,如果没有mock,则我们需要把整个依赖树都构建出来,而使用mock的话就可以将结构分解开,像下面这样:

 

还有一个问题是mock工具那么多,为什么我们要用mockito呢?原因很简单:他非常好用!

他使用执行后验证的模型,语法更简洁并且更加贴近程序员的思考方式,能够模拟类而不仅仅是接口等等。总之如果你想使用mock的话,试用mockito,你不会后悔的:)

 

引用的图摘自http://www.theserverside.com/news/1365050/Using-JMock-in-Test-Driven-Development,那里对mock的使用有很好的介绍。

http://www.sizovpoint.com/2009/03/java-mock-frameworks-comparison.html是一篇非常好的mock工具比较的文章,我就是从它认识的mockito,他也有对mock使用的精彩介绍。

还有一篇文章总结了mockito的好处:http://java.dzone.com/articles/mockito-pros-cons-and-best

 

当然,要想真正了解mockito的好处,就必须写写代码练习一下了。

 

2. Mockito使用实例

这里的代码基本都是从http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html

摘出来的,然后加上了自己的一些学习验证,这个网页挺重要的,会多次提到,以后就简称”网页“了。让我们通过这些实例来看看mockito的强大功能吧:

 

1. 让我们验证一些行为吧

 

 

//Let's import Mockito statically so that the code looks clearer
import static org.mockito.Mockito.*;

//mock creation
List mockedList = mock(List.class);

// using mock object
mockedList.add("one");
mockedList.clear();
mockedList.add("3"); // no verify? OK

// verification
verify(mockedList).add("one");
verify(mockedList).clear();
// verify(mockedList).add("2"); // this will throw an exception
 

首先通过这段代码介绍什么是mock:首先使用Mockito的静态方法mock,我们就可以创建一个类的mock实例,这个mock实例拥有这个List的所有方法接口,并且给这些方法以最基本的实现:如果是返回void,他什么都不做,否则他就返回null或0等基本类型的值。比如中间的三句调用了mock的方法,即使将来不验证也没有任何关系。

 

在验证阶段,当我们验证这个mock的方法add("one")是否被调用的时候,他不会抛出异常,因为我们确实调用了这个方法,但是当我们验证它是否调用add("2")的时候,就会抛出异常,说明我们没有调用过这个方法,此时的测试就会失败。

 

所以验证的意思是”查看我们到底有没有调用过mock的这个方法“。

 

2. 它能提供桩[stub]测试吗?

 

相信这样的场景我们都遇到过,有一个方法的输入是一个List,在这个方法中我们遍历这个List,读取数据,做相应的操作。往常我们可能需要自己创建一个ArrayList,并且将需要的测试的参数add进list中,这样就可以分别进行测试了。下面看看使用mockito是怎么做到的:

 

 

		// You can mock concrete classes, not only interfaces
		LinkedList mockedList = mock(LinkedList.class);

		// stubbing
		when(mockedList.get(0)).thenReturn("first");
		when(mockedList.get(1)).thenThrow(new RuntimeException());

		// following prints "first"
		System.out.println(mockedList.get(0));
		// following throws runtime exception
		System.out.println(mockedList.get(1));
		// following prints "null" because get(999) was not stubbed
		System.out.println(mockedList.get(999));

		// Although it is possible to verify a stubbed invocation, usually it's just redundant
		// See http://monkeyisland.pl/2008/04/26/asking-and-telling
		verify(mockedList, atLeast(2)).get(0);
 

首先我们可以看到mockito是可以mock类而不仅仅是接口的,而stub的语法也非常接近人的阅读习惯:when(mockedList.get(0)).thenReturn("first"); 当调用get(0)的时候返回"first"。

 

这里需要注意以下几点:

【1】mock实例默认的会给所有的方法添加基本实现:返回null或空集合,或者0等基本类型的值。

【2】当我们连续两次为同一个方法使用stub的时候,他只会只用最新的一次。

【3】一旦这个方法被stub了,就会一直返回这个stub的值。

像下面这段代码,你猜会打印什么?

 

 

		when(mockedList.get(0)).thenReturn("first");
		when(mockedList.get(0)).thenReturn("oops");
		System.out.println(mockedList.get(0));
		System.out.println(mockedList.get(0));

  3. 参数匹配

下面我们看看mockito强大的参数匹配机制,当mockito执行verify的时候,它实际上对参数执行的是自然地java方式——equals方法。有事我们需要对参数进行灵活匹配的时候就可以用到”参数匹配器“【argument matchers】了

 

 

		// stubbing using built-in anyInt() argument matcher
		when(mockedList.get(anyInt())).thenReturn("element");

		// following prints "element"
		System.out.println(mockedList.get(999));

		// you can also verify using an argument matcher
		verify(mockedList).get(anyInt());
 

这里的anyInt是mockito内建的众多方法之一,其他可以参考mockito主页上的信息,你也可以调用hamcrest的matchers。

 

警告:若方法中的某一个参数使用了matcher,则所有的参数都必须使用matcher:

 

 

// correct
verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
// will throw exception
verify(mock).someMethod(anyInt(), anyString(), "third argument");

  4. 继续讨论Verification

 

前面的例子都是和网页上的例子一一对应的,现在我们集中讨论一下mockito在verify上提供的强大功能,大部分例子都很简单,所以我基本就是简单的罗列:

 

# 验证方法被调用的次数 网页例子4

 

//using mock 
mockedList.add("once");

mockedList.add("twice");
mockedList.add("twice");

mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");

//following two verifications work exactly the same - times(1) is used by default
verify(mockedList).add("once");
verify(mockedList, times(1)).add("once");

//exact number of invocations verification
verify(mockedList, times(2)).add("twice");
verify(mockedList, times(3)).add("three times");

//verification using never(). never() is an alias to times(0)
verify(mockedList, never()).add("never happened");

//verification using atLeast()/atMost()
verify(mockedList, atLeastOnce()).add("three times");
verify(mockedList, atLeast(2)).add("five times");
verify(mockedList, atMost(5)).add("three times");
 

# 按顺序验证  网页例子6

 

 

// A. Single mock whose methods must be invoked in a particular order
List singleMock = mock(List.class);

//using a single mock
singleMock.add("was added first");
singleMock.add("was added second");

//create an inOrder verifier for a single mock
InOrder inOrder = inOrder(singleMock);

//following will make sure that add is first called with "was added first, then with "was added second"
inOrder.verify(singleMock).add("was added first");
inOrder.verify(singleMock).add("was added second");

// B. Multiple mocks that must be used in a particular order
List firstMock = mock(List.class);
List secondMock = mock(List.class);

//using mocks
firstMock.add("was called first");
secondMock.add("was called second");

//create inOrder object passing any mocks that need to be verified in order
InOrder inOrder = inOrder(firstMock, secondMock);

//following will make sure that firstMock was called before secondMock
inOrder.verify(firstMock).add("was called first");
inOrder.verify(secondMock).add("was called second");

// Oh, and A + B can be mixed together at will
 

# 确保某些方法没有被调用  网页例子7

 

 

//using mocks - only mockOne is interacted
mockOne.add("one");

//ordinary verification
verify(mockOne).add("one");

//verify that method was never called on a mock
verify(mockOne, never()).add("two");

//verify that other mocks were not interacted
verifyZeroInteractions(mockTwo, mockThree);
 

# 从前面的例子我们可以看到,能够很容易地找到冗余的调用  网页例子8

 

 

//using mocks
mockedList.add("one");
mockedList.add("two");

verify(mockedList).add("one");

//following verification will fail 
verifyNoMoreInteractions(mockedList);
 

 

OK,看过Mockito的 mock 和 verify的能力,你可能已经喜欢上Mockito了,不过这只是Mockito强大功能的一部分,下一篇接着翻译我个人用的最多的stub的功能,真的不可错过,看完之后你绝对能够惊叹Mockito的实力的;-)

 

分享到:
评论
1 楼 hw910206 2016-07-06  

相关推荐

    spring集成TestNG与Mockito框架单元测试方法

    本篇文章将深入探讨如何在Spring项目中集成TestNG和Mockito进行单元测试。 TestNG是一个强大的测试框架,它扩展了JUnit的功能,提供了更灵活的测试配置,如并发测试、更丰富的注解、更详尽的测试报告等。首先,你...

    junit单元测试及Mock应用,超详细的PPT实战应用

    总结来说,本文档提供的内容涵盖了单元测试的基本概念、Mock技术的运用、JUnit框架的详细讲解,以及Mockito、MockMVC和Mock.js等工具的使用。通过这些知识,开发者可以构建更健壮的测试体系,提升代码质量和软件工程...

    Junit + Hamcrest + Mockito 单元测试 Jar包

    本资源包含的"Junit + Hamcrest + Mockito 单元测试 Jar包"是一个用于Java应用程序单元测试的工具集合,分别对应了三个流行的测试框架:JUnit、Hamcrest和Mockito。 JUnit是一个开源的Java单元测试框架,广泛应用于...

    SimpleMockito:使用Mockito进行单元测试

    在本教程中,我们将深入探讨如何使用 Mockito 进行单元测试,以及它如何简化我们的测试工作。 1. **Mockito 基本概念** - **Mock 对象**:Mockito 中的 Mock 对象是真实对象的模拟版本,它可以替代被测试对象的...

    Mocks, Mockito, and Spock

    本文将详细介绍Mocks的概念、作用以及如何利用Java中最流行的模拟框架——Mockito进行单元测试。 #### 什么是Mocks? Mocks或者模拟对象是用来模拟复杂的真实对象的行为。当真实对象难以集成到单元测试中时,Mocks...

    springboot + mockito 使用示例代码-原创

    在本文中,我们将深入探讨如何在Spring Boot项目中有效地使用Mockito进行单元测试。Mockito是一个流行的Java单元测试框架,它允许我们创建和配置模拟对象,以便在测试中隔离我们想要验证的代码部分。结合Spring Boot...

    Java mockito单元测试实现过程解析

    本篇文章将深入解析如何使用 Mockito 实现 Java 单元测试。 首先,让我们看一个简单的例子,有一个名为 `ItemService` 的接口,它有一个方法 `getItemNameUpperCase`,该方法根据传入的 `itemId` 从 `...

    单元测试与 Mock 方法

    在实践中,我们通常会遵循以下步骤来使用EasyMock进行单元测试: 1. 创建Mock对象:使用EasyMock.createMock()方法创建一个Mock对象。 2. 配置Mock对象:通过EasyMock.expect()设置Mock对象的方法调用期望,包括参数...

    Mockito+junit5搞定单元测试

    通过以上的介绍,我们了解了如何使用 Mockito 和 JUnit 5 搭配进行单元测试。Mockito 提供了强大的模拟功能,使得测试更加灵活和可控;而 JUnit 5 提供了丰富的测试注解和功能,让编写和组织测试变得更加便捷。结合...

    mockito单元测试

    Mockito是一个广泛使用的Java Mock框架,它允许开发者轻松地创建Mock对象,以便在单元测试中模拟依赖组件的行为。与传统的Mock工具(如EasyMock)相比,Mockito更加直观且易于使用。Mockito的一个显著特点是支持对...

    mockito-1.9.5.zip

    当我们进行单元测试时,Mockito 和 JUnit 结合使用可以创建高效且易于维护的测试代码。 1. **Mockito 框架**: Mockito 允许开发者创建模拟对象(mock objects)来代替真实的依赖,这样在测试中就可以控制这些依赖...

    PowerMock+Mockito-junit测试套件1.6.3版本

    Mockito是一个流行的Java单元测试框架,它提供了创建和配置mock对象的能力。Mockito的主要特点是它的简单性和易用性,允许开发者以一种声明式的方式定义期望行为。 1. **Mock对象创建**:Mockito可以轻松地创建mock...

    Mastering Unit Testing Using Mockito and JUnit.pdf

    《Mastering Unit Testing Using Mockito and JUnit》是一本专注于Java单元测试的专业书籍,它涵盖了使用Mockito和JUnit进行高效测试的各个方面。对于任何在IT行业工作多年,希望提升自身编程测试技能的人来说,这...

    【mockito实战】mockito+junit搞定单元测试,包含测试代码及被测试项目

    将 Mockito 和 JUnit 结合使用,我们可以构建强大的单元测试方案,确保我们的代码在各种预期和非预期情况下都能正确工作。 首先,让我们深入了解一下 Mockito。Mockito 提供了模拟(mocking)和验证(verification...

    EasyMock与Mockito 使用

    单元测试是一种针对代码中最小可测试单元进行验证的方法,而Mocking框架则在这个过程中扮演了关键角色。EasyMock和Mockito是两个广泛使用的Java模拟框架,它们可以帮助开发者在隔离环境中测试代码,避免了依赖其他...

    Mockito-Programming-Cookbook

    **Mockito** 是一个开源的 Java 测试框架,它被设计用于帮助开发者创建模拟对象(mock objects),以便于进行单元测试,支持 **Test-Driven Development (TDD)** 和 **Behavior Driven Development (BDD)** 的开发...

    mockito以及mockMVC的一些使用案例

    Mockito和MockMvc是Java开发中常用的两个单元测试工具,它们在软件开发过程中扮演着重要的角色,帮助开发者确保代码的质量和可维护性。本篇文章将详细介绍这两个库的用途、使用方法以及一些实际案例。 Mockito是一...

    unit-testing:使用Mockito和Easy Mock进行样本单元测试

    在使用Mockito和EasyMock进行单元测试时,我们需要遵循以下步骤: 1. **引入依赖**:在项目中添加Mockito或EasyMock的依赖库,通常通过Maven或Gradle等构建工具完成。 2. **创建模拟对象**:对于被测类依赖的其他类...

    mockito中文文档.zip

    Mockito 是一个流行的 Java 单元测试框架,用于模拟(mock)对象,使得开发者可以在测试代码中隔离依赖,专注于测试单个组件的行为。TDD(Test-Driven Development,测试驱动开发)是它常被结合使用的一种开发模式,...

    使用mockito玩转junit test

    在Java开发过程中,单元测试是确保代码质量的重要环节,而JUnit是Java领域广泛使用的单元测试框架。Mockito则是一个强大的模拟框架,它允许我们在测试中创建和配置模拟对象,以便隔离被测试代码并专注于测试单个行为...

Global site tag (gtag.js) - Google Analytics