Mockito单元测试基本使用

这篇具有很好参考价值的文章主要介绍了Mockito单元测试基本使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文参考:

【码农教程】手把手教你Mockito的使用 - 掘金 (juejin.cn)

java - doReturn().when()与when().thenReturn() - 成长之路 - SegmentFault 思否

单元测试实践篇:Mock_阿里巴巴淘系技术团队官网博客的博客-CSDN博客

阿里是如何进行单元测试培训的?_Hollis Chuang的博客-CSDN博客

【Mockito】Mockito + Junit 5 快速入门_哔哩哔哩_bilibili

1.为什么需要Mock

测试驱动的开发( TDD)要求我们先写单元测试,再写实现代码。在写单元测试的过程中,我们往往会遇到要测试的类有很多依赖,这些依赖的类/对象/资源又有别的依赖,从而形成一个大的依赖树,要在单元测试的环境中完整地构建这样的依赖,是一件很困难的事情。如下图所示:
Mockito单元测试基本使用
为了测试类A,我们需要Mock B类和C类(用虚拟对象来代替)如下图所示:
Mockito单元测试基本使用

2.Mockito 中常用方法

先添加maven依赖:

mockito和junit:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.jxz</groupId>
    <artifactId>MockitoLearning</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>4.3.1</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>
    </dependencies>

</project>

2.1 Mock 方法

mock 方法来自 org.mockito.Mock,它表示可以 mock 一个对象或者是接口。

public static <T> T mock(Class<T> classToMock)
  • classToMock:待 mock 对象的 class 类。
  • 返回 mock 出来的类

实例:使用 mock 方法 mock 一个List类

List mockList = Mockito.mock(List.class);

也可以使用注解来快速模拟

  1. @Mock+MockitoAnnotations.openMocks(this)

也有用@Mock+MockitoAnnotations.initMocks(this)的

package com.jxz;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.List;

import static org.mockito.Mockito.verify;
/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2023/6/19
 */
public class MockExample1 {
    @Mock
    private List mockList;

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

    @Test
    public void testMock(){
        mockList.add(1);
        verify(mockList).add(1);
    }
}
  1. @Mock+@RunWith(MockitoJUnitRunner.class)
package com.jxz;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import java.util.List;

import static org.mockito.Mockito.verify;
/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2023/6/19
 */
@RunWith(MockitoJUnitRunner.class)
public class MockExample2 {
    @Mock
    private List mockList;

    @Test
    public void testMock(){
        mockList.add(1);
        verify(mockList).add(1);
    }
}

2.2 对 Mock 出来的对象进行行为验证和Junit结果断言

一旦mock对象被创建了,Mock对象会记录我们调用的所有交互,也就是各种方法和其调用参数,验证的意思是”查看我们到底有没有输入特定的调用参数,调用过mock的这个方法“,Mockito 中验证的方法是:verify

package com.jxz;

import org.junit.Test;
import org.mockito.Mockito;

import java.util.List;

import static org.mockito.Mockito.verify;
/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2023/6/19
 */
public class Demo {
    @Test
    public void testMock(){
        List mockList = Mockito.mock(List.class);
        mockList.add(1);
        mockList.add("one");

        // verify
        verify(mockList).add(1);
//        verify(mockList).add("two"); //会抛出异常
    }
}

JUnit断言使用到的类是 Assert.

@Test
public void testMock2(){
    List mockList = Mockito.mock(List.class);
    mockList.add(1);

    Assert.assertEquals(1,mockList.get(1));
}

输出:

java.lang.AssertionError: 
Expected :1
Actual   :null

当使用 mock 对象时(这里是mockList),如果不对其行为进行定义(也就是下面的打桩),则 mock 对象方法的返回值为返回类型的默认值(这里为null)。

2.3 测试桩stub

指定mock对象的交互行为逻辑,基本格式when().thenReturn()

when(mockedList.get(0)).thenReturn(“first”)规定当调用get(0)的时候返回"first"

@Test
public void testStub(){
    LinkedList mockList = Mockito.mock(LinkedList.class);
    // stubbing
    when(mockList.get(0)).thenReturn("first");
    when(mockList.get(1)).thenThrow(new RuntimeException());

    System.out.println(mockList.get(0)); //first
    System.out.println(mockList.get(1)); //RuntimeException
}

当我们连续两次为同一个方法使用stub的时候,他只会只用最新的一次。一旦这个方法被stub了,就会一直返回这个stub的值。如下:

@Test
public void testStub2(){
    LinkedList mockList = Mockito.mock(LinkedList.class);
    when(mockList.get(0)).thenReturn("first");
    when(mockList.get(0)).thenReturn("second");
    System.out.println(mockList.get(0));
    System.out.println(mockList.get(0));
}

输出:

second
second

还有一种测试桩指定的方式,即doReturn().when(),本质上也是规定行为。

@Test
public void testDoReturn(){
    A a = new A();
    A mockA = Mockito.mock(A.class);
    Mockito.when(mockA.add(1,2)).thenReturn(5); // 当mockA调用add(1,2),返回5
    System.out.println(mockA.add(1,2)); // 5

    A A2 = new A();
    A mockA2 = Mockito.mock(A.class);
    Mockito.doReturn(5).when(mockA2).add(1,2); // 同样是当mockA调用add(1,2),返回5
    System.out.println(mockA2.add(1,2)); // 5
}

两者本质上就是一个由于执行顺序产生的问题,Mockito.when(mockA.add(1,2)).thenReturn(5),会先执行a + b,即 1 + 2 , 结果本应是3,但由于后面的thenReturn,所以调用该方法时,实际的返回值是5。而Mockito.doReturn(5).when(mockA2).add(1,2)就不会执行a+b的操作,而会直接返回5。区别就是若是一定会执行add()方法,难免会产生无法预估的副作用,比如抛出异常等。

2.4 参数匹配器

参数匹配器可以进行参数的灵活指派。

@Test
public void testMatch(){
    Map mockMap = Mockito.mock(Map.class);
    // 正常打桩测试
    when(mockMap.get("key1")).thenReturn("value1");
    System.out.println(mockMap.get("key1")); //value1

    // 任意String的参数匹配器
    when(mockMap.get(anyString())).thenReturn("value2");
    System.out.println(mockMap.get(anyString())); // value2
    System.out.println(mockMap.get("key2")); // value2
    System.out.println(mockMap.get(1)); // null

    // 多个入参时,要么都使用参数匹配器,要么都不使用,否则会异常, put()返回参数
    when(mockMap.put(anyString(),anyInt())).thenReturn("value3");
    System.out.println(mockMap.put("key3",3)); // value3
    System.out.println(mockMap.put(anyString(),anyInt())); // value3
//        System.out.println("key3",anyInt()); // 异常

    // verify也支持参数匹配
    verify(mockMap,atLeastOnce()).get(anyString()); // 前面交互至少调用了一次get(anyString())
    verify(mockMap).put(anyString(),eq(3)); // 前面至少调用了一次put(anyString(),3)
}

2.5 mock()与spy()

  1. 被 spy 的对象会走真实的方法,而 mock 对象走虚拟对象的方法,返回默认值
  2. spy() 方法的参数是对象实例,mock()方法 的参数是 class

示例:

package com.jxz;

import org.junit.Test;
import org.mockito.Mockito;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2023/6/20
 */
public class SpyAndMock {

    @Test
    public void testSpy(){
        A a = new A();
        A a1 = Mockito.mock(A.class);
        A a2 = Mockito.spy(a);
        System.out.println(a1.add(1,2));
        System.out.println(a2.add(1,2));
    }
}

class A{
    public int add(int a, int b){
        return a+b;
    }
}

输出:

0
3

通过mock生成的对象,会拥有以前的对象的所有方法,但是方法中都没有了功能,就比如上面的a1对应的类可以理解下面这样

A1 extend A {  
    pubic int add(int a, int b) {  
        return 0;  
  }  
}

2.6 @InjectMocks

@InjectMocks和@Mock配合可以简化某个类中,注入类的配置。同时可以在外面对被@Mock的类进行行为指定,从而让其被调用时,产生我们指定的结果。

示例:

要测试的类和方法:

package com.jxz;

/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2023/6/20
 */
public class RegistrationImpl {
    SalesDao salesDao = new SalesDao();
    SaveDao saveDao = new SaveDao();
    public String register(int id, String name){
        String result1 = salesDao.findRep(name);
        System.out.println(result1);

        String result2 = saveDao.save(id, name);
        System.out.println(result2);

        return result1 + "_" + result2;
    }
}

class SalesDao{
    public String findRep(String name){
        return name;
    }
}

class SaveDao{
    public String save(int id, String name){
        return id + name;
    }
}

对应的测试类和方法:文章来源地址https://www.toymoban.com/news/detail-498645.html

package com.jxz;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static org.mockito.Mockito.when;
/**
 * @Author jiangxuzhao
 * @Description
 * @Date 2023/6/20
 */
@RunWith(MockitoJUnitRunner.class)
public class RegistrationImplTest {
    @InjectMocks
    private RegistrationImpl registrationImpl; // 需要被注入mock对象的对象
    @Mock
    private SalesDao salesDao; // RegistrationImpl中注入的类
    @Mock
    private SaveDao saveDao;

    @Test
    public void testRegister(){
        // 进行mock注入类的行为指定
        // 可以看到register方法中调用mock对象打印出来的东西正确
        when(salesDao.findRep("jiangxuzhao")).thenReturn("jiangxuzhao666");  // jiangxuzhao666
        when(saveDao.save(123,"jiangxuzhao")).thenReturn("123jiangxuzhao666"); // 123jiangxuzhao666

        String result = registrationImpl.register(123, "jiangxuzhao");
        Assert.assertEquals(result,"jiangxuzhao666_123jiangxuzhao666"); // 结合mock对象的返回值正确
//        Assert.assertEquals(result,"null"); // org.junit.ComparisonFailure
    }
}

到了这里,关于Mockito单元测试基本使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot单元测试--Mockito+Junit5框架使用

    作为程序员为了提前发现代码bug,优化代码; 通常我们写完某个功能模块代码后都需要写单元测试对代码块进行测试(特别是敏捷开发中);Java项目最常用的单元测试框架即为Junit(目前最新版本为Junit5),SpringBoot本身也整合了该框架。在写单元测试时代码块中的调到第三方接口方

    2024年02月02日
    浏览(45)
  • 【码农教程】手把手教你Mockito的使用

    1)Mockito:简单轻量级的做mocking测试的框架; 2)mock对象:在调试期间用来作为真实对象的替代品; 3)mock测试:在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试; 4)stub:打桩,就是为mock对象的方法指定返回值(可抛出异常); 5)

    2024年02月05日
    浏览(57)
  • 在Spring Boot环境中使用Mockito进行单元测试

    Mockito是一个流行的Java mocking框架,它允许开发者以简单直观的方式创建和使用模拟对象(mocks)。Mockito特别适用于在Spring Boot环境中进行单元测试,因为它能够轻松模拟Spring应用中的服务、存储库、客户端和其他组件。通过使用Mockito,开发者可以模拟外部依赖,从而使单元测

    2024年03月23日
    浏览(49)
  • Spring Boot使用JUnit和Mockito进行Service层单元测试

      在平时的开发当中,一个项目往往包含了大量的方法,可能有成千上万个。如何去保证这些方法产生的结果是我们想要的呢?那么在SpringBoot项目中我们是如何对Service层的方法进行测试的呢?   单元测试是一种软件测试方法,用于测试代码的最小可测试单元。在Java开发

    2024年02月03日
    浏览(52)
  • spring boot 单元测试JUnit5使用Mockito模拟Mock数据调用

    spring boot 单元测试JUnit5使用Mockito模拟Mock数据调用 好大一批新用法,大家静下心来好好看看吧 1. spring boot 使用 Mockito.when().thenReturn()模拟返回值 Mockito 是一种 Java mock 框架,他主要就是用来做 mock 测试的,他可以模拟任何 Spring 管理的 bean、模拟方法的返回值、模拟抛出异常…

    2024年02月15日
    浏览(55)
  • springboot项目使用Junit5 + mockito + jacoco 实现单元测试以及代码覆盖率检查

    在创建springboot项目时会默认添加spring-boot-starter-test依赖,其中已经包含了junit、mockito依赖,根据springboot版本的不同junit和mockito的版本也会有所不同 先说一下各自功能: junit只说一点,junt4和junit5的注解不同,使用方式略有差异,其他不赘述了,基本用法都懂。 mockito是mock的

    2023年04月23日
    浏览(55)
  • Mockito单元测试异常情况

    一、空指针异常 例子: 使用Collectors.groupingBy()进行分组时, 分组值存在null值 。 解决办法:分组值为null时,默认值为空字符,或者让数据不为空。 二、多个参数匹配异常 例如: 如果a和b一个是正常传参(list、map、string…)另一个是任意万能传参(any()、anyList()、anyString(

    2024年02月07日
    浏览(49)
  • 单元测试与Mockito

    系列文章目录和关于我 最近在新公司第一次上手写代码,写了一个不是很难的业务逻辑代码,但是在我写单元测试的时候,发现自己对单元测试的理解的就是一坨,整个过程写得慢,还写得臭。造成这种局面我认为是因为: 对Mockito api是不是很熟悉 没有自己单元测试方法论

    2023年04月22日
    浏览(38)
  • Spring单元测试+Mockito

    一,背景 单元测试基本上是开发逃不过的一个工作内容,虽然往往因为过于无聊,或者过于麻烦,而停止于项目的迭代之中,不了了之了。其实不是开发们懒,而是上头要求的测试覆盖率高,但是又没有好用的工具,导致工作积压,最后只能舍弃掉这部分。 最近发现Spring+

    2024年04月17日
    浏览(42)
  • 单元测试-mockito

    在单元测试中,对于一个类中的方法,常常需要依赖其他类的方法、操作数据dto等对象实例。 方法mock:依赖的方法又可能依赖其他方法,呈现级联的树状结构。 问题:在一些情况下,这个依赖树会很深,其中依赖的一个子方法一旦修改出现问题,如果引起大量的单测不可用

    2024年04月11日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包