Mockito verify Junit5集成 Mockito

news2024/11/15 9:35:36

Mockito 集成 Junit5

在学习Mockito 如何集成 Junit5 之前,先来学习下 Mockito 基础的verify功能。

Maven依赖

本篇博客代码的Maven依赖如下,源码地址

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>6.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>6.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.2</version>
        </dependency>
        <!-- utils -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
        <!-- test scoped -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <version>4.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>31.1-jre</version>
        </dependency>

        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>4.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>3.22.0</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

Mockito Verify

Mockito Verify 方法经常被用于检查校验对象是否发生特定行为 - 即方法. 开发者可在测试方法代码的末尾使用verify方法, 确定是否调用了指定的方法。Mockito Verify主要从以下几个方面对调用行为进行判断

  • 校验是否调用指定方法
  • 校验没有调用其他方法
  • 校验方法调用次数
  • 校验调用方法顺序
  • 校验调用方法的参数

接下来详细学习下 Mockito Verify 相关的API

验证简单调用

  • 验证是否调用指定方法
@Test
    void test1(){
        List<String> list = mock(ArrayList.class);
        list.size();
        // 验证是否调用size 方法
        verify(list).size();
    }
  • 验证没有调用其他方法

    @Test
        void test2(){
            List<String> list = mock(ArrayList.class);
            // 验证list 对象没发生额外调用
            verifyNoMoreInteractions(list);
        }
    
  • 验证从没调用过指定方法

    @Test
        void test3(){
            List<String> list = mock(ArrayList.class);
            list.size();
            //从未调用过clear 方法
            verify(list,never()).clear();
        }
    

验证调用次数

  • 验证仅调用一次

        @Test
        void test0(){
            List<String> list = mock(ArrayList.class);
            list.size();
            // times(1), only(),atLeast(1) 都能实现一次调用的验证
            //verify(list,times(1)).size();
            //verify(list,only()).size();
            verify(list,atLeast(1)).size();
        }
    
  • 验证至少调用次数

    @Test
        void test0(){
            List<String> list = mock(ArrayList.class);
            list.size();
            // 最少一次调用验证
            verify(list,atLeastOnce()).size();
        }
    
  • 验证最多调用次数

    @Test
        void test0(){
            List<String> list = mock(ArrayList.class);
            list.size();
    			//最多一次
            verify(list,atMostOnce()).size();
           // 最多10次
            verify(list,atMost(10)).size();
        }
    

验证调用顺序

@Test
    void test3(){
        List<String> list = mock(ArrayList.class);
        list.size();
        list.add("hello");
        list.clear();
        InOrder inOrder = Mockito.inOrder(list);
        inOrder.verify(list).size();
        inOrder.verify(list).add(anyString());
        inOrder.verify(list).clear();
    }

验证调用参数

  • 验证指定参数

        @Test
        void test6(){
            List<String> list = mock(ArrayList.class);
            list.add("hello");
            verify(list).add("hello");
            // 以下两种 验证参数类型
            verify(list).add(anyString());
            verify(list).add(any(String.class));
        }
    
  • 验证捕获参数

     @Test
        void test7(){
            List<String> list = mock(ArrayList.class);
            list.addAll(Lists.<String> newArrayList("someElement"));
            ArgumentCaptor<List<String>> captor = ArgumentCaptor.forClass(List.class);
            verify(list).addAll(captor.capture());
    				// 捕获参数 并验证是否包含特定值
            final List<String> value = captor.getValue();
            assertThat(value).contains("someElement");
        }
    

集成Junit5

有了之前的基础后,接下来来学习下Mockito 如何集成 Junit5,了解Junit5如何对Mockito进行扩展。大致的流程:

  • 首先先创建Junit5扩展,该扩展使用@mock自动创建mock对象,模拟任何对象属性或者方法
  • 然后在Junit5测试类中使用Mockito扩展

应用场景

假设现在有一个项目,团队需要基于SpringBoot MVC的架构模式进行开发。由于业务足够复杂,分工细致。你被要求开发 service层的业务逻辑,Repository数据操作层由其他团队负责,双方根据约定好的接口进行协同开发。

由于你的专业技术能力过硬,开发效率较高,因此已经完成了开发工作。但是其他团队Repository没有完成,只提供了对应的接口。现在您需要对整理流程进行集成测试,此时Mock排上用场。

基础代码

  • User 实体类

    @Data
    @ToString
    @NoArgsConstructor
    public class User {
        private Integer id;
        private String name;
        private int age;
    
        public User(String name,int age){
            this.name = name;
            this.age  = age;
        }
    }
    
  • service接口

    import com.andy.spring.junit5.mockito.User;
    
    public interface UserService {
    
        User register(User user);
    }
    
  • service实现类

    import com.andy.spring.junit5.mockito.User;
    import com.andy.spring.junit5.mockito.repository.UserRepository;
    import com.andy.spring.junit5.mockito.service.UserService;
    
    public class DefaultUserService implements UserService {
        private UserRepository userRepository;
    
        public DefaultUserService(UserRepository userRepository) {
            this.userRepository = userRepository;
        }
    
        @Override
        public User register(User user) {
            validate(user);
            User insertedUser = userRepository.insert(user);
            return insertedUser;
        }
    
        private void validate(User user) {
            if(user.getName() == null) {
                throw new RuntimeException("用户名称不能为空");
            }
    
            if(userRepository.isUsernameAlreadyExists(user.getName())) {
                throw new RuntimeException("用户名称已存在");
            }
        }
    }
    
  • Repository 接口定义

    import com.andy.spring.junit5.mockito.User;
    
    public interface UserRepository {
    
        User insert(User user);
        boolean isUsernameAlreadyExists(String userName);
    
    }
    

验证测试

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
    private UserService userService;
    @Mock
    private UserRepository userRepository;
    private User user;

    //每次运行测试方法都进行初始化
    @BeforeEach
    void init(){
        userService = new DefaultUserService(userRepository);
        //输入任意字符串 参数校验都返回false
        lenient().when(userRepository.isUsernameAlreadyExists(any(String.class)))
                .thenReturn(false);
    }

    @Test
    void test1(){
        user = new User("kobe",40);
        when(userRepository.insert(any(User.class))).then(new Answer<User>() {
            int sequence = 1;
            @Override
            public User answer(InvocationOnMock invocation) throws Throwable {
                //模拟插入db后,对ID主键进行赋值
                User user = (User) invocation.getArgument(0);
                user.setId(sequence++);
                return user;
            }
        });
        userService = new DefaultUserService(userRepository);
        // When
        User insertedUser = userService.register(user);
        System.out.println("insertedUser : " + insertedUser);
        // Then 验证是否调用 insert 方法 参数为user
        verify(userRepository).insert(user);
        assertNotNull(user.getId());
    }
}

以上代码很容易理解,值得注意的是需要在class类上加上**@ExtendWith(MockitoExtension.class)**注解。测试截图

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/64302.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享107个小清新ppt模板,总有一款适合您

PPT下载链接&#xff1a;https://pan.baidu.com/s/1WqaR_29avEgq46iTSLKfmw?pwd5r81 提取码&#xff1a;5r81 源码下载链接&#xff1a;ppt.rar - 蓝奏云 采集的参数 page_count 1 # 每个栏目开始业务content"text/html; charsetgb2312"base_url "https:…

大一学生《Web编程基础》期末网页制作 基于HTML+CSS+JavaScript响应式个人主页相册介绍模板

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

UNIX环境高级编程_文件IO_文件描述表

这篇文件记录文件描述表。 2 文件描述符表 2.1 什么是文件描述符表 当运行一个程序时&#xff0c;内核会创建进程表task_struct。当open 打开文件后&#xff0c;会在进程表中创建相应的结构体来记录打开的文件&#xff0c;这个结构体就是文件描述符表。 2.2 task_struct 与…

Apple M1 开启HiDPI的新方法,无需虚拟屏,无需SwitchResX

之前折腾2K屏开HiDPI时记录过三种方法&#xff1a; 2020年03月&#xff1a;SwitchResX 开启HiDPI时显示Not installed的解决办法 2020年11月&#xff1a;升级macOS Big Sur 后 HIDPI失效的解决办法 2021年12月&#xff1a; Apple M1 开启HiDPI的新方法&#xff0c;无需关闭SIP&…

MySQL学习笔记(十三)count(*),count(id),count(1),count(字段)区别

count count 是MySQL的一个查询数量统计的函数&#xff0c;我们在平常的工作中经常会用到&#xff0c;count(*),count(id),count(1),count(字段)这4种写法有什么区别呢&#xff1f; //星号 select count(*) from user; //常数 select count(1) from user; //id(主键) select …

片内总线在cpu扮演什么角色?他为什么能实现高效,不同的CPU为什么采用不同的总线协议?

文章目录各种新型片上总线维度&#xff08;Degree&#xff09;跳&#xff08;Hop&#xff09;和跳数&#xff08;Hop Count&#xff0c;HC&#xff09;直连拓扑和路由器Intel的Ring和Mesh总线双Ring结构Mesh Bus结论片上总线&#xff0c;也称作片上网络&#xff08;Network on …

毕业设计-基于机器视觉的火灾烟雾检测识别系统-yolo

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java基于网络安全维护的机房设备管理19rya

对于计算机专业的学生最头疼的就是临近毕业时的毕业设计,对于如何选题,技术选型等这些问题,难道了大部分人,确实,还没毕业的学生对于这些问题还比较陌生,只有学习的理论知识,没有实战经验怎么能独自完成毕业设计这一系列的流程,今天我们就聊聊如何快速应对这一难题. 比较容易的…

LSM Tree

LSM Tree 的存储模型&#xff0c;包括 Tidb&#xff0c;HBase等 特点 通过将大量的随机写转换为顺序写&#xff0c;从而极大地提升了数据写入的性能&#xff0c;虽然与此同时牺牲了部分读的性能。 只适合存储 key 值有序且写入大于读取的数据&#xff0c;或者读取操作通常是…

vueX持久化存储插件

场景&#xff1a;我们在做vue项目时&#xff0c;会遇到存储一些公共值&#xff0c;这样方便在不同的页面去调用这些值 vue中有个vuex&#xff0c;一般我们都存储在这里&#xff0c;这样在每个页面都能够调用 但是&#xff0c;当页面刷新了&#xff0c;这些值就被自动清理掉了 这…

第七届 Sky Hackathon 笔记集合贴

Alex_McAvoy--------NVIDIA 7th SkyHackathon&#xff08;二&#xff09;开发套件的安装与测试 Alex_McAvoy--------NVIDIA 7th SkyHackathon&#xff08;三&#xff09;语音数据集的制作 Alex_McAvoy--------NVIDIA 7th SkyHackathon&#xff08;四&#xff09;Nemo ASR 模型训…

vue.js ES6对象字面量的增强写法

1.属性的增强写法 ES5的写法&#xff1a; 运行效果 ES6的写法&#xff1a; 运行效果 2.函数的增强写法 ES5的写法&#xff1a; ES6的写法&#xff1a; 完整代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><meta name"…

基于Javamail的邮件收发系统(系统+论文+开题报告+任务书+外文翻译+文献综述+答辩PPT)

毕业设计&#xff08;论文&#xff09; &#xff08; 20 届&#xff09; 论文&#xff08;设计&#xff09;题目 基于Javamail的邮件收发系统 作 者 二级学院、专业 班 级 指导教师&#xff08;职称&#xff09; 论 文 字 数 论文完成时间 20年月日 基于JavaMail的邮件…

169-Rust和Solana环境配置

之前写过一篇Rust和Solana环境配置的 应该说写得是非常非常好 并不是说博文写得好 而是说写得非常非常的必要 比如我现在就是想要搞Rust和Solana配置 但是好久好久没搞了 已经完全忘记了 看到那一篇博文的时候就感觉想起来了很多 如果可以参考那篇完整做下来的话 就会…

是时候展示给大家这5款压箱底的软件了

是时候把自己压箱底的软件都发出来了&#xff0c;软件都是小巧耐用&#xff0c;不带广告的&#xff0c;赶紧下载起来吧&#xff01;就算暂时用不到的&#xff0c;也可以收藏起来等需要的时候再来下载&#xff01; 1.PPT演示——Focusky 一个高效的动画 PPT 演示软件&#xff0…

Linux学习-71-GRUB手动安装方法

16.13 GRUB手动安装方法 需要手工安装 GRUB 主要有两种情况&#xff1a; Linux 系统原先不是使用 GRUB 作为引导程序而现在想要使用 GRUB 来作为引导程序&#xff1b;MBR 中的引导程序被覆盖&#xff0c;需要在 MBR 中重新安装 GRUB&#xff0c;如先安装了 Linux 系统&#xf…

主成分分析的基本原理

目录 什么是主成分分析&#xff1f; 主成分分析的步骤 根据什么选择主成分&#xff1f; 怎样解释主成分&#xff1f; 特征值、方差解释率及碎石图 载荷系数与共同度 什么是主成分分析&#xff1f; 主成分的概念由Karl Pearson在1901年提出的。他是考察多个 变量间相关性…

Qt扫盲-Qt Creator IDE使用总结

Qt Creator IDE使用总结一、欢迎页1. 最近项目2. 示例3. 教程二、编辑页1. 左侧菜单区1. 工具栏2. 项目目录常用操作介绍1. 项目名2. 中间编码区1.顶部工具区2.编码区的常用功能1. 文件操作2. 类的一些方便操作1、Follow Symbol Under Cursor2. 查找和替换3. Refactor4. F1帮助…

AP1236 线性LDO稳压IC 工作原理图分享

深圳世微半导体有限公司&#xff0c;专业研发DC/DC降压恒流车灯IC&#xff0c;我们有一流的研发团队&#xff0c;良好的服务&#xff0c;做一流品质的产品&#xff0c;所有产品均提供配套方案和技术支持 供应多种DC/DC降压恒流方案选型表&#xff1a; AP5160 外置MOS电流20MA-…

构造一个m行n列的二维数组(mln的取值均小于等于4, mln均由键盘输入),并由键盘输入数组元素的值,并且按照矩阵的形式输出

构造一个m行n列的二维数组(mln的取值均小于等于4&#xff0c; mln均由键盘输入),并由键盘输入数组元素的值&#xff0c;并且按照矩阵的形式输出 Scanner sc new Scanner(System.in); System.out.println("请输入行"); int m sc.nextInt(); System.out.println(&quo…