mock的笔记,包含基本概念和使用使用技巧

一、mock的概念

1.mockito知识体系

2.为什么要使用mock

Mock 可以理解为创建一个虚假的对象,或者说模拟出一个对象,在测试环境中用来替换掉真实的对象,以达到我们可以。验证该对象的某些方法的调用情况,调用了多少次,参数是多少。给这个对象的行为做一个定义,来指定返回结果或者指定特定的动作

3.mock的依赖

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <scope>5.8.2</scope>
</dependency>

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <scope>4.3.1</scope>
</dependency>

4.Mock方法

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

public static <T> T mock(Class<T> classToMock)

对于以下简单方法的mock实例:

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

在类名上,鼠标右键,Generate--> Test 勾上要测试的方法,就会创建一个测试类

 @Test
    void add() {
        //mock方法来自org.mockito.Mock,它表示可以mock一个对象或者接口
        //官方文档中public static <T> T mock(Class<T> classToMock),这个classToMock 是待 mock 对象的 class 类
        //1.mock 一个对象的class类
        Random random = Mockito.mock(Random.class,"test");
        //2.使用random的nextInt方法
        System.out.println(random.nextInt());
        //3.验证是校验待验证的对象是否发生过某些行为,Mockito 中验证的方法是: verify
        Mockito.verify(random).nextInt();
        //4.Verify 配合 times() 方法,可以校验某些操作发生的次数
        Mockito.verify(random, Mockito.times(1)).nextInt();
    }

4.给 Mock 对象打桩和断言

打桩的意思就是给 mock 对象规定一行的行为,使其按照我们的要求来执行具体的操作

Random random = Mockito.mock(Random.class,"test");
//5.打桩 用when方法
Mockito.when(random.nextInt()).thenReturn(100);

打桩之后会用断言来验证;打桩的是期望值

断言使用到的类是Assertions.里面的两个参数,第一个是期望值,第二个是实际值;

Random random = Mockito.mock(Random.class,“test”);
Assertions.assertEquals(100, random.nextInt());

当使用mock 对象时,如果不对其行为进行定义,则mock 对象方法的返回值为返回类型的默认值。  

5.@mock 注解

想当于是快速的创建mock,模拟方法。不再用

Random random = Mockito.mock(Random.class,“test”);    

而是直接在类中,方法上面:

@Mock
private Random random; 

 

@Mock 注解的官方注意事项

Shorthand for mocks creation - @Mock annotation
Important! This needs to be somewhere in the base class or a test runner: 

快速 mock 的方法,使用 @mock 注解。

mock 注解需要搭配MockitoAnnotarions.openMocks(testClass)方法一起使用  

@Mock
    private Random random;

    @Test
    void add() {
        //使@Mock注解生效
        MockitoAnnotations.openMocks(this);
        //打桩
        Mockito.when(random.nextInt()).thenReturn(100);
        //断言
        Assertions.assertEquals(100,random.nextInt());
    }

6.@BeforeEach和 @AfterEach

 @Mock
    private Random random;

    @BeforeEach
    void setUp(){
    System.out.println("测试前的准备");
    //使@Mock注解生效
    MockitoAnnotations.openMocks(this);
    }

    @Test
    void add() {
    //打桩
    Mockito.when(random.nextInt()).thenReturn(100);
    //断言
    Assertions.assertEquals(100,random.nextInt());
    }

    @AfterEach
    void after(){
    System.out.println("测试结束");
    }

7.Spy 方法与 @Spy 注解

spy()方法与mock()方法不同的是

1.被 spy 的对象会走真实的方法,而 mock 对象是模拟的方法 2.spy() 方法的参数是对象实例,mock 的参数是 class

 @Spy
    private MockitoDemo mockitoDemo;

    @BeforeEach
    void setUp(){
        System.out.println("测试前的准备");
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void add() {
        /*
        //这是直接运行,和验证的写法
        int addResult = mockitoDemo.add(1, 2);
        Assertions.assertEquals(3,addResult);
        */


        //更应该进行打桩,设定一个返回值
        //当使用mock 对象时,如果不对其行为进行定义,则mock 对象方法的返回值为返回类型的默认值
        Mockito.when(mockitoDemo.add(1,2)).thenReturn(3);
        //然后进行断言,没有打桩走真实方法,打桩走模拟的方法
        Assertions.assertEquals(3,mockitoDemo.add(1,2));;
    }

8.    .thenThtow()和.thenCallRealMethod()

/*
        //.thenThtow() 抛出异常,因为在又抛出异常的地方,要考虑到正常通过和抛出异常两面
        Mockito.when(mockitoDemo.add(1,2)).thenThrow(new RuntimeException("mockitoDemo.add的运行时异常"));
        Assertions.assertEquals(3,mockitoDemo.add(1,2));
        */

        /*
        //.thenCallRealMethod() 走真实的方法。
        // 这里的场景是@Mock的情况中,可以先走一次mock方法,再走一次真实的方法
        Mockito.when(mockitoDemo.add(1,2)).thenCallRealMethod();
        Assertions.assertEquals(3,mockitoDemo.add(1,2));
        */

--classToMock待 mock 对象的 class 类 --返回mock 出来的类

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

Random random = Mockito.mock(Random.class,“test");

9.验证

验证是校验待验证的对象是否发生过某些行为,Mockito 中验证的方法是: verify。

verify(mock).someMethod("some arg");
verify(mock,times(1)).someMethod("some arg");

 使用 verify 验证: Verify 配合 time() 方法,可以校验某些操作发生的次数

10.mock静态方法 Mockito.mockStatic()

静态方法需要更换mockito依赖

<!--mockito-inline 比 mockito-core 支持的mock方法更多,比如mock静态方法等。
且包含了mockito-core且这两个依赖不能同时使用-->

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <scope>4.3.1</scope>
</dependency>

代码实现

/**
 * desc:mock静态方法
 * 包括无参和有参的静态方法
 * @author zsc
 * @createTime 2023/10/16 8:53
 */
class StaticDemoTest {
    /**
    * range
    * 有参静态方法 的mock测试
    * @param
    * @return void
    * @author zsc
    * @date 2023/10/16
    **/
    @Test
    void range() {
        //mock方法的导入
        MockedStatic<StaticDemo> staticDemoMockedStatic = Mockito.mockStatic(StaticDemo.class);
        //打桩
        staticDemoMockedStatic.when(()->StaticDemo.range(2,6)).thenReturn(Arrays.asList(10,11,12));
        //断言
        Assertions.assertTrue(StaticDemo.range(2,6).contains(10));

        //关闭mock
        staticDemoMockedStatic.close();
    }

    /**
    * name
    * 有参静态方法的mock测试
    * @param
    * @return void
    * @author zsc
    * @date 2023/10/16
    **/
    @Test
    void name() {
        //mock方法的导入
        MockedStatic<StaticDemo> staticDemoMockedStatic = Mockito.mockStatic(StaticDemo.class);
        //打桩
        staticDemoMockedStatic.when(StaticDemo::name).thenReturn("bilibili");
        //断言
        Assertions.assertEquals("bilibili",StaticDemo.name());
        //关闭mock
        staticDemoMockedStatic.close();
    }

}

关闭mock :staticDemoMockedStatic.close();一定要关闭,不然每个@Test都可以运行的情况下,整体的class StaticDemoTest{}是不能运行的

11.@InjectMocks

模拟(mock)一些依赖的对象来隔离被测试类的外部依赖比如

@Mock
private UserMapper userMapper
    
@InjectMocks
private UserServiceImpl userService;

@InjectMocks注解会根据类型(或名称)匹配,在被测试类中自动查找并注入模拟对象

	try {
            userService.queryUserPage(queryUserPageBO);
        } catch (Exception e) {
            Assertions.assertTrue(e instanceof CustomException);
        }
        
  这里用到了userService.queryUserPage()一定会调用mapper层,但是上面@InjectMocks会把mock出来的userMapper加入进来。不会去测试类外面去找。

二.使用的一些思路技巧:

1.idea的分屏

以在 IntelliJ IDEA 中开启分屏功能。如果您的键盘布局与默认配置不同,也可以通过打开 "Settings/Preferences" -> "Keymap" 菜单,搜索 "split" 来查找并配置适合您的分屏快捷键

我的快捷键

Ctrl + Shift +CAPS LK

2.对于编写哪些类的单元测试

写类的 mock 取决于你的测试目标和测试策略。 mock 的目的是用虚拟对象替代真实对象,以模拟特定行为或返回值,从而进行单元测试。

在编写单元测试时,通常会针对不同层次的组件进行测试。如果你的目标是测试 Controller 层的代码逻辑,那么你可能需要编写 Controller 层的 mock 对象来模拟请求和验证 Controller 的行为。这样你可以在不涉及实际服务调用的情况下对 Controller 的逻辑进行测试。

然而,如果你的目标是测试 Service 层的代码逻辑,你可以创建 Service 层的 mock 对象来模拟对其他依赖组件(如 DAO 层、外部服务等)的调用,而不需要关心 Controller 层。这样可以更加专注地测试 Service 层的业务逻辑。

总而言之,编写哪些类的 mock 取决于你的测试目标和测试策略。根据需要,你可以选择编写 Controller 层的 mock、Service 层的 mock 或其他相关组件的 mock,以便针对不同的层次进行单元测试

3.测试过程中

打桩时需要传入参数的首先可以试试传入any();

打桩返回参数是list,比较复杂,尝试用arraylist

类似以下的用法:

Mockito.when(userMapper.queryUserList(any(),any())).thenReturn(null);
Mockito.when(userMapper.queryUserPage(querryUserPagePO,pageParams)).thenReturn(arrayList);

 请注意any()是来自于mockito-core依赖的

import static org.mockito.ArgumentMatchers.any;
而any()来自于
Maven: org.mockito:mockito-core:3.6.28 (mockito-core-3.6.28.jar)

所以mock测试的时候采用mockito-core 依赖
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <scope>4.3.1</scope>
</dependency>

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <scope>5.8.2</scope>
</dependency>

然后需要遇到空指针错误,需要传入一个有值的参数;

如果是int,string等基础类型可以直接传值;这个时候any()一般也可以用;

像是ToracledemoUserBO 这种有字段的类型,

首先尝试new出来。毕竟直接new出来的类也不是null的;

其次可以向new出来的类中去set数据。

三、代码中的部分实例

1.测试类最上面的注解

 

2.打桩和断言的使用

四、参考文档

Mockito编写Service层单元测试icon-default.png?t=N7T8https://blog.csdn.net/u012760435/article/details/90643872 mock详细教程入门这一篇就够了icon-default.png?t=N7T8https://blog.csdn.net/m0_58026506/article/details/126897449

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mock.js 是一个用于生成随机数据的 JavaScript 库,可以用于前后端分离开发中模拟接口数据,方便前端开发调试。 Mock.js 的基本使用步骤如下: 1. 安装 Mock.js 库 可以通过 npm 安装 Mock.js,命令如下: ``` npm install mockjs --save-dev ``` 2. 编写模拟数据 在前端开发中,通常需要模拟后端接口的返回数据。使用 Mock.js 可以很方便地生成模拟数据。 示例代码: ```javascript import Mock from 'mockjs' // 模拟一个接口返回数据 Mock.mock('/api/user', { 'name': '@name', // 随机生成一个中文名字 'age|1-100': 100, // 随机生成一个 1-100 之间的数字 'gender|1': ['男', '女'], // 随机生成一个性别 'email': '@EMAIL', // 随机生成一个邮箱 'phone': /^1[3456789]\d{9}$/ // 随机生成一个手机号 }) ``` 3. 拦截 Ajax 请求 Mock.js 可以拦截 Ajax 请求,根据请求的 URL 和请求方法返回模拟数据。 示例代码: ```javascript import Mock from 'mockjs' // 模拟一个接口返回数据 Mock.mock('/api/user', { 'name': '@name', 'age|1-100': 100, 'gender|1': ['男', '女'], 'email': '@EMAIL', 'phone': /^1[3456789]\d{9}$/ }) // 拦截 Ajax 请求 Mock.mock('/api/user', 'get', { code: 200, message: 'OK', data: Mock.mock('@user') }) ``` 4. 使用模拟数据 在前端开发中,可以通过 Ajax 请求获取模拟数据,在页面上展示模拟数据。 示例代码: ```javascript import axios from 'axios' axios.get('/api/user') .then(res => { console.log(res.data) }) .catch(err => { console.error(err) }) ``` 以上是 Mock.js 的基本使用方法,还有更多高级用法,可以参考官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值