Mockito单元测试

Mockito简介

  Mockito是一个单元测试框架,需要Junit的支持。在我们的项目中,都存在相当多的依赖关系,当我们在测试某一个业务相关的接口或则方法时,绝大多数时候是没有办法或则很难去添加所有的依赖,因为这中间肯定会涉及到别的业务逻辑。而在开发过程中,可能这个模块根本都还没有。那可咋怎啊?这个时候一种叫做mock测试的方式就顺势崛起。通过模拟出依赖对象,并对涉及到的方法设置预期值。这样你就可以只关心依赖方法的结果,从而完成对本模块的单元测试。这种方法还细化了测试粒度。棒棒的。想做更多了解就自行解决了。

Mockito的使用

  1. 首先来一个最基本的Junit测试
@Test
    public void stringUtilTest(){

        boolean b = StringUtil.isEmpty("good");
        Assert.assertTrue("must true",b);//断言

    }

  像这种对工具类的测试,一般很少依赖别的类,所以直接断言之。当然断言的类型还有很多,这里就试用一下对boolean的断言。

  2.  mockito对依赖的模拟,并设置预期返回值。针对依赖的方法有返回值。在单元测试时,我们不想也最好不要直接调用依赖的方法的具体实现,因为所依赖的方法可能本来就没有经过测试,还存在bug,难道这时候又要为依赖的方法再写一个test case?或则这个方法由别人开发,但是目前还没有实现,难道要自己去实现?you`d better say NO!看看下面怎么做的。

  

import org.mockito.Mockito;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @auther guozg
 */

public class MockTest {
    @Test
    public void mockReturnTest(){
        // mock creation 创建模拟对象
        UserDao mockeDao = Mockito.mock(UserDao.class);
        UserService s = new UserService();//创建被测试类
        s.setDao(mockeDao);//为被测试类添加依赖
        Mockito.when(mockeDao.getData(Mockito.anyString())).thenReturn(4).thenReturn(1);//为模拟对象方法设置预期返回值,
        boolean b = s.checkDate();                          //多个thenReturn表示多次调用时,依次返回
        boolean b1 = s.checkDate();              //如果设置的预期个数少于调用次数,超过的调用都返回最后一个。
        boolean b2 = s.checkDate();              //如果设置的预期个数多于调用次数,任然依次返回相应值
        Mockito.verify(mockeDao, Mockito.times(1)).getData(Mockito.anyString());
        Assert.assertTrue("must true",b);
        Assert.assertFalse("must true",b1);
        Assert.assertFalse("must true",b2);
    }
}

class UserService{
    UserDao dao ;
    public boolean checkDate(){     String id = "123";
        if(dao.getData(id)>3){
            return true;
        }
        return false;
    }

    public UserDao getDao() {
        return dao;
    }

    public void setDao(UserDao dao) {
        this.dao = dao;
    }

}

class UserDao{
    public Integer getData(String id){ return 0; } }

  这里随便举的简单例子,我需要对UserService.checkDate()做一个单元测试。而这时候UserService对UserDao存在依赖关系。所以这时候为了隔离UserDao的实现,通过Mockito.mock模拟出UserDao对象。并为掉用的getData()设置了预期返回值。然后调用要测试的方法、验证设置预期的方法是否被调用,最后对测试方法的返回值断言。这里指的一说的是Mockito.anyString()这个方法,他的主要目的是表示在模拟状态下,getData()的参数可以是任意字符串。当然也可以直接给定一些参数,如果模拟对象指定的参数和实际逻辑给的参数不一致,这时候不会返回实际UserDao中getData()的值也不会返回设置的预期值,而是返回的返回类型的默认值,比如int就返回0,boolean返回false等。Mockito还有很多类似的方法,比如anyInt(),anyBoolen(),anyCollection()等等。

  还有就是看到thenReturn()方法,这是在为依赖方法设置预期返回值,这个就可以有自己控制了。然后看到可以连续多次设置,这个在代码里面有注释了,由于对语言表达能力的不自信,来个表格展示一下。

                

  然后还有一个验证方法是否被调用Mockito.verify()这个方法的参数是模拟的对象、VerificationMode。这个VerificationMode就是一个验证模型,可以是代表调用次数、是否调用、超时验证,等等(有些我也不知道干啥的,要进一步研究)。verify()可以理解为断言。

  3.  对于有返回值的方法,我们可以通过设置预期来控制,并且隔离掉具体的实现。但是对于没有返回值得方法呢?不着急,Mockti为我们提供了另一种方式可以控制模拟对象的方法的行为,包括逻辑处理、抛异常、返回值、执行原方法逻辑以及什么都不做。doReturn()|doThrow()| doAnswer()|doNothing()|doCallRealMethod();下面先来测试一下doAnswer();首先,我们会在UserDao 中加一个setUser(User u)方法,为user设置年龄,然后通过UserService的checkData中调用。然后我们通过doAnwser去控制setUser的逻辑。

package com.centnet.train.user.controller;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @auther guozg
 */

public class MockTest {

    @Test
    public void doAnwserTest(){
        // mock creation 创建模拟对象
        UserDao mockeDao = Mockito.mock(UserDao.class);
        UserService s = new UserService();//创建被测试类
        User u = new User();
        s.setDao(mockeDao);//为被测试类添加依赖
        Mockito.doAnswer(new Answer() {
            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                User u = invocationOnMock.getArgument(0);
                u.setName("ggg");
                return null;
            }
        }).when(mockeDao).setUser(u);
        Mockito.when(mockeDao.getData()).thenReturn(4);
        boolean b = s.checkDate(u);

        Mockito.verify(mockeDao, Mockito.times(1)).getData();
        Mockito.verify(mockeDao, Mockito.times(1)).setUser(u);
        Assert.assertTrue("must true",b);
        Assert.assertNotNull("控制不成功",u.getName());        Assert.assertNull("原逻辑被执行",u.getAge());
    }
}

class UserService{
    UserDao dao ;
    public boolean checkDate(User u){
        dao.setUser(u);
        if(dao.getData()>3){
            return true;
        }
        return false;
    }

    public UserDao getDao() {
        return dao;
    }

    public void setDao(UserDao dao) {
        this.dao = dao;
    }

    public void setUser(User user){
        user.setAge(12);

    }

}

class UserDao{
    public Integer getData(){
        return 0;
    }

    public void setUser(User user){
        user.setAge(12);
    }
}

class User{

    String name;
    Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

  我们在UserDao中只设置了age,但是对age为空的断言却成功了。这表示原逻辑没有执行。再看看对Name的不为空断言,也通过了。这表示对setUser的行为被doAnwser()控制了。doAnwser()需要传入对一个Anwser对象,这个对象有点和代理对象类似。如果调用方法有返回值,则anwer()的返回值就是它。invocationOnMock.getArgument(0)获取参数,然后就可以对参数操作啦啦啦啦。其他几个也可以试试,比如改成调用原逻辑,Mockito.doCallRealMethod().when(mockeDao).setUser(u)。哎呀呀,这时候user的age就有了而且还是18.重点:对于在测试;类中的方法不用设置预期,会调用原逻辑,但是对于依赖类的方法就要设置预期了,否则会对有返回值的仅返回类型默认值、无返回值的直接啥都不做走人。

  好了,下班了,先到这里,以后有新的接触,在添加进来,以上例子略显粗犷,如不慎入坑,请包涵!(说得好像有人会看似的!!!要真有人看,基于以上例子可灵活处理。)

原文地址:https://www.cnblogs.com/guozhigang/p/9884969.html

时间: 2024-11-05 13:51:11

Mockito单元测试的相关文章

JUnit + Mockito 单元测试(二)

JUnit 是单元测试框架.Mockito 与 JUnit 不同,并不是单元测试框架(这方面 JUnit 已经足够好了),它是用于生成模拟对象或者直接点说,就是"假对象"的工具.两者定位不同,所以一般通常的做法就是联合 JUnit + Mockito 来进行测试. 入门 首先是配置 Mock 对象,看看例子怎么写的. [java] view plain copy List mock = mock( List.class ); when( mock.get(0) ).thenReturn

Mockito单元测试框架学习

一.问题:如何将mock的类自动注入到待测类,特别是在没有setter方法的情况下. 解答: 前提:待测的service类及其依赖的其他类都是处在被spring管理中的. 做法:在测试类中,只要将待测的类标注为@InjectMocks,将其以来的其他类标注为 @Mock, 就可以使用MockitoAnnotations.initMocks(this);这句话自动将待测类依赖的类注入,如果依赖类在spring的管理下有自己的name,那么甚至在待测类中都不需要写setter方法. 例: 1.待测类

探索构架开发J2EE项目的自动化体系

序目 Eclipse IDE开发环境 Maven构建自动化编译打包项目 NEXUS  私有Maven仓库 SVN源码管理 junit+mockito 单元测试与mock框架 集成 JaCoCo分析单元测试的覆盖率 Jenkins集成 Sonar分析源代码质量 Glassfish Web容器发布 人人都在谈敏捷开发的时代,所谓工欲善其事必先利其器……在此之前得有jdk环境,在这不多说了. Maven 集成jacoco分析单测试的覆盖率 在父项目的pom.xml上加入如下配置 <build> &l

单元测试--Junit和Mockito

说到测试,大家都不会陌生,从我们开始学习编程开始,就知道测试.测试和编程就像两个双胞胎似的,可是,显然我们更钟情于双胞胎中的一个--编程.一些人可能对测试了然于胸,却匮乏于行动,一些人也可能对测试只是闻其名不知其意.下面这篇博文就是给大家在零基础上讲解一下Java中单元测试的使用. ---------------------------什 么 是-----------------------------    首先来说说,究竟什么是单元测试?单元测试是指对软件中的最小可测试单元进行检查和验证.对

使用Mockito进行单元测试【2】—— stub 和 高级特性[转]

一篇中介绍了Mockito的基本信息,现在接着介绍Mockito强大的stub功能 2. Mockito使用实例 5. 对连续的调用进行不同的返回 (iterator-style stubbing) 还记得在实例2中说道当我们连续两次为同一个方法使用stub的时候,他只会使用最新的一次.但是在某一个方法中我们确实有很多的调用怎么办呢?mockito当然想到这一点了: Java代码   when(mock.someMethod("some arg")) .thenThrow(new Ru

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

本文转自:http://qiuguo0205.iteye.com/blog/1443344 1. 为什么使用Mockito来进行单元测试? 回答这个问题需要回答两个方面,第一个是为什么使用mock?mock其实是一种工具的简称,他最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为. 比如一段代码有这样的依赖: 当我们需要测试A类的时候,如果没有mock,则我们需要把整个依赖树都构建出来,而使用mock的话就可以将结构

[单元测试]Java单元测试,基于Mockito的第一次尝试

Mockito 进行Mock单元测试入门 个人理解: 单元测试:对程序中最小的运行单元就行测试,java中通常是一个类 Mock的作用是在JUnit的基础上,对于依赖进行模拟,人为的将集成测试封闭成黑盒的单元测试. 其他的具体用发和概念可以自行google,网上已经有很多解释,这里只给像我这样刚刚入门,第一次写单元测试的人做一个引导. 这里主要讲一下Mockito中 when(...).thenReturn(...) 的使用时机: 在单元测试的方法中,但有需要依赖于服务A的方法B的返回的时候,需

单元测试及框架简介 --junit、jmock、mockito、powermock的简单使用

转 单元测试及框架简介 --junit.jmock.mockito.powermock的简单使用 2013年08月28日 14:33:06 luvinahlc 阅读数:6413 标签: 测试工具单元测试Junit实例Mockito 更多 个人分类: 单元测试 推荐一个新手学习Junit4的博客地址:http://www.cnblogs.com/eggbucket/archive/2012/02/02/2335697.html        点击打开链接 一.单元测试 单元测试概念: 所谓MT(M

Mockito一个采用Java编写用于单元测试的Mocking框架

參考:https://github.com/mockito/mockito Mockito一个采用Java编写用于单元测试的Mocking框架 https://www.ctolib.com/mockito.html 原文地址:https://www.cnblogs.com/highpointengineer/p/10977004.html