当前位置: 首页 > news >正文

Mockito verify Junit5集成 Mockito

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

相关文章:

  • 大连宇都环境 | 成都5月水科技大会暨技术装备成果展览会
  • 美国国防部数据网格参考架构概述(上)
  • 根据顶层的id递归查询出全部子节点
  • 新版本Qt Creator安装配置
  • 用Python将Word文件另存为任意支持的格式
  • clickhouse与oracle传输数据
  • 【前端的讲解】
  • 普中51单片机学习(8*8LED点阵)
  • Java开发的核心模式 - MVC
  • 数据结构·顺序表实现通讯录
  • Neoverse S3 系统 IP:机密计算和多芯片基础设施 SoC 的基础
  • Self-attention与Word2Vec
  • 文件或者文件夹的忽略
  • 年产2万吨山楂酒工厂的设计-发酵工段及车间的设计(lunwen+任务书+cad图纸)
  • 【LIN总线测试】——LIN主节点调度表测试
  • 写一个flutter程序2
  • 给定一个数组arr,长度为N且每个值都是正数,代表N个人的体重。再给定一个正数 limit,代表一艘船的载重。
  • 【大道模式】状态模式 - State Pattern(审核状态流转)
  • 协议-序列化-http-Cookie-Session-https
  • 数据结构—Map集合
  • SpringMVC对消息转换器的处理相关
  • Linux-文件压缩解压
  • [附源码]计算机毕业设计JAVA医药管理系统
  • [附源码]计算机毕业设计基于SpringBoot+Vue的健身房会员系统的设计与实现
  • 9 特色聚类
  • python中的集合详解
  • pringboot面向爱宠人群的宠物资讯系统36as8计算机毕业设计-课程设计-期末作业-毕设程序代做
  • Flink系列之Flink中StateBackend深入剖析和应用
  • Java可变参数和集合工具类Collections的详细介绍
  • 网站构建初级教程
  • 项目管理逻辑:老板为什么赔钱的项目也做?为什么害怕你闲着?
  • Spring Boot 框架整合 MyBatis 连接数据库,详细说明