首页 > 其他分享 >Mockito用法总结

Mockito用法总结

时间:2024-08-30 16:51:32浏览次数:9  
标签:总结 Goods Mockito goodsMock println 用法 class out

Mockito的是用来做什么的

Mockito主要用于单元测试过程中模拟被调用方法的

依赖

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.8.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>4.8.0</version>
    <scope>test</scope>
</dependency>

版本说明,3.4之前Mockito不能模拟静态方法,所以一般和powermock一起用3.4以后已经不需要powermock,
下面是 powermock的最新版本已 2020年11月1日的版本,所以建议直接使用mockito 3.4以后的版本

<!-- Power Mock -->
<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-module-junit4</artifactId>
  <version>2.0.9</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-api-mockito2</artifactId>
  <version>2.0.9</version>
  <scope>test</scope>
</dependency>

创建Mock对象

可以使用 @Mock,@Spy,@InjectMocks 创建模拟对象

@RunWith(MockitoJUnitRunner.class)
public class MockItoTest {
    
    
    @Mock
    GoodsExMapper goodsExMapper;

    @Mock
    SqlSessionFactory sqlSessionFactory;

    @InjectMocks
    GoodsServiceImpl goodsServiceImpl;

    @Mock
    GoodsServiceImpl goodsServiceImplMock;

    @Spy
    private GoodsServiceImpl goodsServiceImplSpy;
    
    
    //省略

}

也可以代码里面创建,如果没有在类上写上@RunWith(MockitoJUnitRunner.class,可以使用 MockitoAnnotations.openMocks(this)来让当前teset类里面的@Mock @Spy 等注解生效

    /**
     * 初始化Mock对象
     */
    @Test
    public void initMock() {
        //如果没有在类上写上@RunWith(MockitoJUnitRunner.class,可以使用 MockitoAnnotations.openMocks(this)来让当前teset类里面的@Mock @Spy 等注解生效
        System.out.println( goodsExMapper );
        MockitoAnnotations.openMocks(this);
        System.out.println( goodsExMapper );


        //除了使用@Mock @Spy 以外还能使用对应的方法常见mock对象
        Goods goodsMock = Mockito.mock(Goods.class);
        Goods goodsSpy = Mockito.spy(Goods.class);
    }

@Mock @InjectMocks @Spy 的区别

  • @Mock的对象所有方法都不会真实调用,会根据返回值类型的默认值返回,可以通过Mockito.when插桩
  • @InjectMocks 总是会调用真的实现方法,可以通过Mockito.when插桩,插桩值影响返回值,真实的方法依旧会被调用
  • @Spy 默认调用真实的实现方法,可以通过Mockito.return插桩,插桩后不会调用真实的方法

@Test
public void Mock() {
    //@Mock 的对象方法不会被真实调用,放回默认值
    System.out.println("goodsServiceImplMock.add(Goods.randomGoods() ) = " + goodsServiceImplMock.add(Goods.randomGoods()));
}
@Test
public void injectMocks() {
    //@InjectMocks的对象 方法真实的调用,并且活自动注入mock类(@mock,@spy 标注的成员变量的自动注入)
    System.out.println("goodsServiceImpl.add(Goods.randomGoods() ) = " + goodsServiceImpl.add(Goods.randomGoods()));
}

@Test
public void spy() {
    //@Spy 的对象方法被真是的调用,但是里面的成员变量不会自动加载,,使用里面的成员变量会报空指针
    System.out.println("goodsServiceImplSpy.add(Goods.randomGoods() ) = " + goodsServiceImplSpy.add(Goods.randomGoods()));
}

模拟普通方法

  • Mockito.when 的时候被mock方法会调用一次,并且对@InjectMock能用
  • Mockito.doReturn 方法不会被调用,并且对@InjectMock不能用
  • 被模拟的的时候 @Mock,@Spy 不会调用原来的方法,@InjectMocks总会调用真实的方法,然后修改返回值

@Test
public void mockMethod() {

    //@mock Mockito.when 有效
    //@mock Mockito.doReturn 有效
    //GoodsServiceImpl impl = goodsServiceImplMock;

    //@Spy Mockito.when 无效
    //@Spy Mockito.doReturn 有效
   // GoodsServiceImpl impl = goodsServiceImplSpy;

    //@InJect Mockito.when 有效
    //@InJect Mockito.doReturn 无效
    GoodsServiceImpl impl = goodsServiceImpl;


    ReflectionTestUtils.setField(impl,"goodsExMapper",goodsExMapper);
    System.out.println("goodsServiceImplSpy.add(new Goods())1 = " + impl.add(new Goods()));


    //Mockito.when( impl.add( Mockito.any(Goods.class) ) ).thenReturn( 99 );
    Mockito.doReturn(88).when( impl ).add( Mockito.any( Goods.class ));
    //给 add方法指定插桩,固定返回99

    //这里的方法插桩以后不会真实的调用
    System.out.println("goodsServiceImplSpy.add(new Goods())2 = " + impl.add(new Goods()));

}

final方法的模拟

@Test
public void mockFinalMethod() {
    GoodsEntity goodsMock = Mockito.mock(GoodsEntity.class);
    GoodsEntity goodsSpy = Mockito.spy(GoodsEntity.class);

    System.out.println("goodsMock.finalMethd()1 = " + goodsMock.finalMethd());
    Mockito.when( goodsMock.finalMethd() ).thenReturn( new GoodsEntity("GoodsMock") );
    System.out.println("goodsMock.finalMethd()2 = " + goodsMock.finalMethd());



    System.out.println("goodsSpy.finalMethd()1 = " + goodsSpy.finalMethd());
    Mockito.when( goodsSpy.finalMethd() ).thenReturn( new GoodsEntity("goodsSpy") );
    System.out.println("goodsSpy.finalMethd()2 = " + goodsSpy.finalMethd());
}

final方法的模拟 mock。spy对象对 Mockito.when/Mockito.doReturn都有效

@Test
public void mockFinalMethod2() {
    GoodsEntity goodsMock = Mockito.mock(GoodsEntity.class);
    GoodsEntity goodsSpy = Mockito.spy(GoodsEntity.class);

    System.out.println("goodsMock.finalMethd()1 = " + goodsMock.finalMethd());
    Mockito.doReturn(new GoodsEntity("GoodsMock")).when(goodsMock).finalMethd();
    System.out.println("goodsMock.finalMethd()2 = " + goodsMock.finalMethd());


    System.out.println("goodsSpy.finalMethd()1 = " + goodsSpy.finalMethd());
    Mockito.doReturn(new GoodsEntity("GoodsSpy")).when(goodsSpy).finalMethd();
    System.out.println("goodsSpy.finalMethd()2 = " + goodsSpy.finalMethd());
}

给私有属性设置值(非私有属性也能用)

@Test
public void setField() throws NoSuchFieldException {
    //设置spring的方法
    ReflectionTestUtils.setField(goodsServiceImplSpy,"goodsExMapper",goodsExMapper);

    //mockito 3.3
    //FieldSetter.setField(goodsServiceImplSpy, GoodsServiceImpl.class.getDeclaredField("goodsExMapper"), goodsExMapper);

    //mockito 3.5(用法java的反射,不如直接用spring那个)
    new InstanceField( GoodsServiceImpl.class.getField("goodsExMapper"), goodsServiceImplSpy).set( goodsExMapper );

    System.out.println("goodsServiceImplSpy.add(Goods.randomGoods() ) = " + goodsServiceImplSpy.add(Goods.randomGoods()));
}

模拟静态方法

/**
 * 3.4开始支持,3.4以前需要使用powerMock
 *
 */
@Test
public void mockStaticMethod() {
    Goods goods1 = new Goods();
    goods1.setName("good1");

    //mock所有静态方法,都是返回默认值
    MockedStatic<Goods> goodsMockedStatic = Mockito.mockStatic(Goods.class);

    //模拟Goods.randomGoods方法,指定桩
    goodsMockedStatic.when(Goods::randomGoods).thenReturn( goods1 );

    GoodsEntity goods = GoodsEntity.randomGoods();
    GoodsEntity goods2 = GoodsEntity.randomGoods2();
    System.out.println(JSONUtil.toJsonStr( goods ));
    System.out.println(JSONUtil.toJsonStr( goods2 ));
}

构造方法模拟

@Test
public void mockConstructionMethod() {
    MockedConstruction<Goods> goodsMockedConstruction = Mockito.mockConstruction(Goods.class);
    //模拟构造方法可以关闭
    //goodsMockedConstruction.close();

    Goods goods = new Goods();
    Goods goods2 = new Goods("1");
    System.out.println( goods);
    System.out.println( goods2);
    System.out.println( JSONUtil.toJsonStr(goods));
    System.out.println( JSONUtil.toJsonStr(goods2));
    //goodsMockedConstruction.constructed()) 里面记录着通过 mock构造的对象
    System.out.println( JSONUtil.toJsonStr(goodsMockedConstruction.constructed()));

}

返回值模拟

@Test
public void retuen() {
    GoodsEntity goodsMock = Mockito.mock(GoodsEntity.class);
    GoodsEntity goodsSpy = Mockito.spy(GoodsEntity.class);

    //指定返回值
    Mockito.doReturn("data").when(goodsMock).getData();
    System.out.println( goodsMock.getData() );

    //指定什么也不做
    Mockito.doNothing().when(goodsSpy).setData(Mockito.anyString());
    goodsSpy.setData("a");
    System.out.println( goodsSpy.getData() );

    //调用真实方法
    Mockito.doCallRealMethod().when(goodsMock).setData(Mockito.anyString());
    Mockito.doCallRealMethod().when(goodsMock).getData();
    goodsMock.setData("data2");
    System.out.println( goodsMock.getData() );


    //doAnswer之定义方法mock 过程,和 doReturn只能改返回值
    Mockito.doAnswer(param->{
        System.out.println(JSONUtil.toJsonStr( param.getArguments() ));
        System.out.println(param.getMock());
        return param.getMethod().getName();
    }).when(goodsMock).getData();

    System.out.println( goodsMock.getData() );

    //doAnswer之定义方法mock 过程,和 doReturn只能改返回值
    Mockito.doAnswer(param -> {
        System.out.println(JSONUtil.toJsonStr(param.getArguments()));
        GoodsEntity mock = (GoodsEntity) param.getMock();
        ReflectionTestUtils.setField(mock, "data", param.getArgument(0));
        return param.getMethod().getName();
    }).when(goodsSpy).setData(Mockito.anyString());
    goodsSpy.setData("aaa");
    System.out.println( goodsSpy.getData() );

    //抛出异常
    Mockito.doThrow(new RuntimeException("1111")).when( goodsMock ).getDes();
    //goodsMock.getDes();

}

参数匹配

@Test
public void argumentMatchers() {
    //Mockito 集成了 ArgumentMatchers,里面有很多辅助参数匹配的方法
    //参数匹配是用于对指定参数放回不同的返回值


    GoodsEntity goodsMock = Mockito.mock(GoodsEntity.class);
    GoodsEntity goodsSpy = Mockito.spy(GoodsEntity.class);

    //int匹配
    Mockito.doReturn(1).when(goodsMock).square(ArgumentMatchers.anyInt());
    //空参数匹配
    Mockito.doReturn("1100").when(goodsMock).m2(ArgumentMatchers.isNull());
    //指定在开头(也提供了指定结尾,或者从包含)
    Mockito.doReturn("abc开头").when(goodsMock).m2(ArgumentMatchers.startsWith("abc"));

    //自定义匹配,所有的xxxTHat接口都是可以实现ArgumentMatcher接口,然后自定义匹配规则
    Mockito.doReturn("123开头").when(goodsMock).m2( ArgumentMatchers.argThat(new ArgumentMatcher<String>() {
        @Override
        public boolean matches(String arg) {
            return arg.startsWith("123");
        }
    }) );




    int square = goodsMock.square(10);
    System.out.println( square );

    String rt = goodsMock.m2("1234" );
    System.out.println("rt = " + rt);


}

验证一个方法是否被调用

@Test
public void verify() {
    Goods goodsMock = Mockito.mock(Goods.class);

    goodsMock.getDes();
    //goodsMock.getDes();

    //默认是验证倍调用了一次
    //Mockito.verify(goodsMock).getDes();

    //没有调用
    // Mockito.xxx方法返回 VerificationMode 类型的就是验证用于验证次数的
    //Mockito.verify(goodsMock, Mockito.never()).getDes();

    //至少多少次
    //Mockito.verify(goodsMock, Mockito.atLeastOnce()).getDes();
    //Mockito.verify(goodsMock, Mockito.atLeast(2)).getDes();

    //至多调用2次
    //Mockito.verify(goodsMock, Mockito.atLeast(2)).getDes();


    //5秒以后再验证是否被调用(验证调用一次)
    Mockito.verify(goodsMock, Mockito.after(5000)).getDes();

}

Mockit可以和TestMe之类的IDEA插件配合生成单元测试代码

插件

image-20240830152414588

可以直接生成

image-20240830152513753

选择使用的是Mockito还是powermock,Junit4还是Junit5
image-20240830152545233

生成的测试代码,生成以后一般需要做一些调整,生成的时候已经对DAO等服务调用模拟了,我们要做的是确认这些方法模拟是我们需要的已经修改对面模拟值。

package com.lomi.service.impl;

import com.lomi.entity.Goods;
import com.lomi.entity.JsonItem;
import com.lomi.entity.in.BatchIn;
import com.lomi.mapper.GoodsExMapper;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.Arrays;
import java.util.List;

import static org.mockito.Mockito.*;

public class GoodsServiceImplTest {
    @Mock
    GoodsExMapper goodsExMapper;
    @Mock
    SqlSessionFactory sqlSessionFactory;

    @InjectMocks
    GoodsServiceImpl goodsServiceImpl;

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

    @Test
    public void testAdd() throws Exception {
        when(goodsExMapper.insert(any(Goods.class))).thenReturn(0);

        goodsServiceImpl.add(new Goods("name"));
    }

    @Test
    public void testAddBatch() throws Exception {
        goodsServiceImpl.addBatch(Arrays.<Goods>asList(new Goods("name")));
        verify(goodsExMapper).addBatch(any(List.class));
    }

    @Test
    public void testAddBatchJson() throws Exception {
        goodsServiceImpl.addBatchJson(Arrays.<JsonItem>asList(new JsonItem()));
        verify(goodsExMapper).addBatchJson(any(List.class));
    }

    @Test(expected = NullPointerException.class)
    public void testAddBatchByExecutorType() throws Exception {
        when(goodsExMapper.insert(any(Goods.class))).thenReturn(0);
        when(sqlSessionFactory.openSession(any(ExecutorType.class))).thenReturn(null);

        goodsServiceImpl.addBatchByExecutorType(new BatchIn());
    }

    @Test(expected=RuntimeException.class)
    public void testTransationKafkaMsg() throws Exception {
        when(goodsExMapper.insert(any(Goods.class))).thenReturn(0);

        goodsServiceImpl.transationKafkaMsg(new Goods("name"), Boolean.TRUE);
    }

    @Test(expected = RuntimeException.class)
    public void testTestRetryable() throws Exception {
        when(goodsExMapper.insert(any(Goods.class))).thenReturn(0);

        goodsServiceImpl.testRetryable(new Goods("name"));
    }

    @Test
    public void testRecover() throws Exception {
        goodsServiceImpl.recover(new Exception("message", new Throwable("message")), new Goods("name"));
    }
}

多次插桩

/**
 * 多次插桩,会被覆盖,如果需要依次放回多个值,需要在一次插桩的时候指定
 */
@Test
public void n() {
    Goods goodsMock = Mockito.mock(Goods.class);
    Mockito.doReturn("1","2").doReturn("3").when(goodsMock).getDes();
    Mockito.when( goodsMock.getDes()).thenReturn("a","b").thenReturn("c");


    //前三次分别返回a,b,c,之后全是放回c
    System.out.println( goodsMock.getDes() );
    System.out.println( goodsMock.getDes() );
    System.out.println( goodsMock.getDes() );
    System.out.println( goodsMock.getDes() );
    System.out.println( goodsMock.getDes() );
    System.out.println( goodsMock.getDes() );
}

异常处理方法

 	@Rule
    public  ExpectedException exception = ExpectedException.none();
    /**
     * 异常处理方法1
     */
    @Test
    public void e1() {
        exception.expect(RuntimeException.class);
        exception.expectMessage("Runtime exception occurred");
        throw new RuntimeException("Runtime exception occurred");
    }

    /**
     * 异常处理方法2
     */
    @Test(expected = Exception.class)
    public void e2() {
        ExpectedException exception = ExpectedException.none();
        exception.expect(Exception.class);
    }

PowerMock静态方法模拟

@RunWith(PowerMockRunner.class)和相应的@PrepareForTest注解。

@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticClass.class)
public class StaticMethodTest {

    @Test
    public void testStaticMethod() throws Exception {
        // 配置静态方法的模拟行为
        PowerMockito.mockStatic(StaticClass.class);
        when(StaticClass.someStaticMethod()).thenReturn("mockedValue");

        // 调用依赖于静态方法的代码并验证其行为
        MyClass myClass = new MyClass();
        String result = myClass.methodUnderTest();

        assertEquals("mockedValue", result);

        // 验证静态方法是否被正确调用
        verifyStatic(StaticClass.class);
        StaticClass.someStaticMethod();
    }
}

其他的一些说明

  • 参数匹配的时候Mockito.anyxxx不包括null

  • Mockito.verify方法只是验证方法是否被调用了指定次数,不是调用

  • Mockito.whe和Mockito.doReturn用于模拟方法

  • Mockito.doThrow用于模拟抛出异常

  • void 返回值 使用 Mockito.doNothing 方法

  • thenAnswer里面可以自定义模拟方法返回值和调用过程

  • Mockito 继承了 ArgumentMatchers,里面有很多辅助参数匹配的方法

  • Mockito.xxx方法返回 VerificationMode 类型的就是验证用于验证次数的

  • 插桩了,不调用会报错?
    貌似有的版本会报错,我用的4.8不会

  • @SpyBean 和 @MockBean spring 容器用
    如果是@RunWith(SpringRunner.class)方式的spring环境运行,@SpyBean,@MockBean会用模拟对象替换spring容器里面的对象。

标签:总结,Goods,Mockito,goodsMock,println,用法,class,out
From: https://www.cnblogs.com/cxygg/p/18389053

相关文章

  • Vue 过滤器(Filter)的理解与用法
    Vue.js是一个渐进式JavaScript框架,它提供了丰富的功能来构建用户界面。其中,过滤器(Filter)是一个非常有用的特性,它允许我们在模板中对数据进行格式化处理。本文将详细介绍Vue过滤器的概念、用法以及一些最佳实践。1.过滤器的基本概念1.1什么是过滤器?过滤器是Vue提供的一种......
  • Linux中cd命令的基本用法!
    cd命令是Linux中最常见的命令之一,全拼changedirectory,其命令主要用于切换当前工作目录,本篇文章为大家介绍一下Linux中cd命令的常见用法,一起来看看吧。常见的cd命令用法:1、进入当前工作目录下的目录:cd./2、进入其他目录:cd/home/user/documents/3、......
  • C++学习随笔——C++11的array、forward_list、tuple的用法
    1.std::arraystd::array是C++11引入的一个封装了原生数组的容器,它结合了C++标准库容器的优点和C风格数组的效率。#include<array>#include<iostream>intmain(){std::array<int,5>arr={1,2,3,4,5};//初始化一个大小为5的数组//访问元素......
  • 差模电感与共模电感总结
    差模电感与共模电感总结差模干扰信号和共模干扰信号差模干扰信号是两个输入电源线之间反方向构成的电流回路信号。共模干扰信号是两个输入线上同方向与大地构成的电流回路信号。简而言之:差模信号就是两个大小相等、方向相反的信号。共模信号就是两个大小相等、方向相同的信......
  • 2024.8.29 总结
    上午&中午按计划学了李超线段树,照着题解写过了模板题。然后本来打算去做题单里的一道Ynoi紫来练dsuontree,于是边写题解边想,结果写着写着就不会了,发现好像dsuontree不太好做,好像是两只log的。还可能大概会一个单log大常数线段树合并。看题解区发现有跑出dfs序后......
  • 三分钟总结开源流程表单的优势特点
    实现流程化办公,可以借助低代码技术平台、开源流程表单的优势特点。作为当前较为理想的平台产品,低代码技术平台凭借够灵活、好操作、可视化界面的优势特点,得到了通信业、医疗、高校等很多行业客户朋友的喜爱与支持。今天一起来看看开源流程表单的优势特点,一起了解它为何能助力企业......
  • MySQL 支持两种主要类型的备份方法:物理备份和逻辑备份。这两种备份方法各有优缺点,适用
    物理备份物理备份是指直接备份MySQL数据库的物理文件,包括数据文件、日志文件、配置文件等。物理备份通常分为冷备份(脱机备份)和热备份(联机备份)。冷备份(ColdBackup)定义: 在数据库完全停止的情况下进行的备份。特点:  简单快速,因为只需复制文件。可以在任何时间点进行。不需要锁......
  • 设计模式总结(二):结构型模式
    @TOC结构型模式1.代理模式1.1静态代理用户只关心接口功能,而不在乎谁提供了功能。上图中接口是Subject接口真正实现者是上图的RealSubject,但是它不与用户直接接触,而是通过代理。代理就是上图中的Proxy,由于它实现了Subject接口,所以它能够直接与用户接触。用户调用Proxy的时候,Pr......
  • 阿里云服务器部署Sonic总结
    1.购买阿里云服务器访问阿里云官网,选择合适的云服务器购买购买成功后创建ECS云服务器下载AlibabaCloudClient创建AccessKey并保存打开AlibabaCloudClient,添加账号2.安装docker选择操作—>启动远程连接(SSH)snapinstalldockerdocker-vdocker-compose-v3.......
  • PbootCMS网站常见错误提示总结
    一些初涉相关领域的新朋友在进行pbootcms的安装过程中,往往会频繁遭遇一些错误状况。接下来,为您详细罗列pbootcms于后台抑或前台所呈现出的各类问题以及相应的解决办法。 1、Parseerror:syntaxerror,unexpected':',expecting'{'inwww\core\function\handle.phpon......