java mock及Mockito实战

来源:互联网 发布:智能优化算法的优缺点 编辑:程序博客网 时间:2024/05/29 16:49

mock是什么?

无论是敏捷开发、持续交付,还是测试驱动开发(TDD)都把单元测试作为实现的基石。随着这些先进的编程开发模式日益深入人心,单元测试如今显得越来越重要了。在敏捷开发、持续交付中要求单元测试一定要快(不能访问实际的文件系统或数据库),而TDD经常会碰到协同模块尚未开发的情况,而mock技术正是解决这些问题的灵丹妙药。

mock技术的目的和作用是模拟一些在应用中不容易构造或者比较复杂的对象,从而把测试与测试边界以外的对象隔离开。

当然,测试这件事大部分开发者大部分做的并不好,总想着完成线上的要求,后期再补上测试用例,有句话“Later is Never”(等以后就是永远不会了),所以自觉地把测试重视起来是很重要地事情了。

java mock 和 junit 有什么区别与联系?

在做单元测试的时候,我们会发现我们要测试的方法会引用很多外部依赖的对象,比如:(发送邮件,网络通讯,记录Log, 文件系统 之类的)。 而我们没法控制这些外部依赖的对象。 为了解决这个问题,我们需要用到Stub和Mock来模拟这些外部依赖的对象,从而控制它们。

JUnit是单元测试框架,可以轻松的完成关联依赖关系少或者比较简单的类的单元测试,但是对于关联到其它比较复杂的类或对运行环境有要求的类的单元测试,模拟环境或者配置环境会非常耗时,实施单元测试比较困难。而这些“mock框架”(Mockito 、jmock 、 powermock、EasyMock),可以通过mock框架模拟一个对象的行为,从而隔离开我们不关心的其他对象,使得测试变得简单。(例如service调用dao,即service依赖dao,我们可以通过mock dao来模拟真实的dao调用,从而能达到测试service的目的。当然,Spring全家桶有 Spring-test这个神器,此处是考虑全面的情况。)

模拟对象(Mock Object)可以取代真实对象的位置,用于测试一些与真实对象进行交互或依赖于真实对象的功能,模拟对象的背后目的就是创建一个轻量级的、可控制的对象来代替测试中需要的真实对象,模拟真实对象的行为和功能。

Mockito使用

1、引入依赖

<dependency>        <groupId>org.mockito</groupId>        <artifactId>mockito-all</artifactId>        <version>1.9.5</version>        <scope>test</scope>    </dependency>

2、使用语法示例

package com.leo;import org.junit.Assert;import org.junit.Test;import java.util.List;import static org.mockito.Mockito.*;/** * Created by LEO on 2017/9/2. */public class SimpleTest {    @Test    public void simpleTest1(){        //创建mock对象,参数可以是类,也可以是接口        List<String> list = mock(List.class);        //设置方法的预期返回值        when(list.get(0)).thenReturn("helloworld");        String result = list.get(0);        //验证方法调用(是否调用了get(0))        verify(list).get(0);        //junit测试        Assert.assertEquals("helloworld", result);    }}

创建mock对象不能对final,Anonymous ,primitive类进行mock。下面是一些其他常用地方法:

设定返回异常:

when(list.get(1)).thenThrow(new RuntimeException("test excpetion"));

没有返回值的void方法与其设定(支持迭代风格,第一次调用donothing,第二次dothrow抛出runtime异常)

doNothing().doThrow(new RuntimeException("void exception")).when(list).clear();  list.clear();  list.clear();  verify(list,times(2)).clear();  

方法调用的验证(具体的调用次数、至少一次,一次也没有)

List<String> mockedList = mock(List.class); mockedList.add("three times");  mockedList.add("three times");  mockedList.add("three times");  //验证是否调用了三次verify(mockedList, times(3)).add("three times");  //never()等同于time(0),一次也没有调用  verify(mockedList, times(0)).add("never happened");  verify(mockedList, never()).add("never happened");//atLeastOnece/atLeast()/atMost()  verify(mockedList, atLeastOnce()).add("three times");  verify(mockedList, atLeast(2)).add("twice");  verify(mockedList, atMost(5)).add("three times");  

快速创建Mock对象

public class ArticleManagerTest {   @Mock private ArticleCalculator calculator;      @Mock private ArticleDatabase database;      @Mock private UserProvider userProvider;      @Before      public void before(){          MockitoAnnotations.initMocks(this);      }}

3、测试覆盖率

这个部分我们看一下Intellj IDEA提供地代码测试覆盖率的工具

首先编写一个类

package com.leo;/** * Created by LEO on 2017/9/2. */public class ClassA {    public String sayHello(){        return "Hello!";    }    public String sayGoodBye(){        return "GoodBye!";    }}

写出他的测试类,可以选中上面那个类的类型,按Ctrl+Shift+T,即可快速创建测试类

package com.leo;import org.junit.Assert;import org.junit.Test;/** * Created by LEO on 2017/9/2. */public class ClassATest {    @Test    public void sayHello() throws Exception {        ClassA classA = new ClassA();        Assert.assertEquals("Hello!", classA.sayHello());    }}

运行这个测试类的时候,选择“run ‘ClassATest’ with Coverage”,就可以看到如下的结果:
效果图

原创粉丝点击