SpringBoot中Mockito单元测试入门

 更新时间:2021年06月01日 10:34:12   作者:小小工匠  
单元测试在很多地方都用的到,本文主要介绍了SpringBoot中Mockito单元测试入门,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

Mock 测试

Mock 测试就是在测试过程中,创建一个假的对象,避免你为了测试一个方法,却要自行构建整个 Bean 的依赖链。

举个例子:

类 A 需要调用类 B 和类 C,而类 B 和类 C 又需要调用其他类如 D、E、F 等,假设类 D 是一个外部服务,那就会很难测,因为你的返回结果会直接的受外部服务影响,导致你的单元测试可能今天会过、但明天就过不了了。

在这里插入图片描述

而当我们引入 Mock 测试时,就可以创建一个假的对象,替换掉真实的 Bean B 和 C,这样在调用B、C的方法时,实际上就会去调用这个假的 Mock 对象的方法,而我们就可以自己设定这个 Mock 对象的参数和期望结果,让我们可以专注在测试当前的类 A,而不会受到其他的外部服务影响,这样测试效率就能提高很多。

在这里插入图片描述

What's Mockito

Mockito 是一种 Java Mock 框架,主要就是用来做 Mock 测试的,它可以模拟任何 Spring 管理的 Bean、模拟方法的返回值、模拟抛出异常等等,同时也会记录调用这些模拟方法的参数、调用顺序,从而可以校验出这个 Mock 对象是否有被正确的顺序调用,以及按照期望的参数被调用。

像是 Mockito 可以在单元测试中模拟一个 Service 返回的数据,而不会真正去调用该 Service,通过模拟一个假的 Service 对象,来快速的测试当前想要测试的类。

目前在 Java 中主流的 Mock 测试工具有 Mockito、JMock、EasyMock等等,而 SpringBoot 目前默认的测试框架是 Mockito 框架。

使用 Mockito

pom依赖

 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

在这里插入图片描述

Demo Code

一个 UserService,两个方法

  • getUserById() -------------> 调用 UserDao 这个 bean的 getUserById()
  • insertUser() -------------> 调用 UserDao 这个 bean的 insertUser()
@Component
public class UserService {
    
    @Autowired
    private UserDao userDao;

    public User getUserById(Integer id) {
        return userDao.getUserById(id);
    }

    public Integer insertUser(User user) {
        return userDao.insertUser(user);
    }
}

【POJO对象】

public class User {
    private Integer id;
    private String name;
    //省略 getter/setter
}

【常规操作】

如果这时候我们先不使用 Mockito 模拟一个假的 userDao Bean,而是真的去调用一个正常的 Spring Bean 的 userDao 的话, 注入 userService Bean,然后去调用方法,而他会再去调用 userDao 取得数据库的数据,然后我们再对返回结果做 Assert 断言检查。

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {

    //先普通的注入一个userService bean
    @Autowired
    private UserService userService;

    @Test
    public void getUserById() throws Exception {
        //普通的使用userService,他里面会再去调用userDao取得数据库的数据
        User user = userService.getUserById(1);
        
        //检查结果
        Assert.assertNotNull(user);
        Assert.assertEquals(user.getId(), new Integer(1));
        Assert.assertEquals(user.getName(), "John");
    }
}

【Mockito】

但是如果 userDao 还没写好,又想先测 userService 的话,就需要使用 Mockito 去模拟一个假的 userDao 出来。

具体怎么搞呢?

在 userDao 上加上一个 @MockBean 注解

当 userDao 被加上这个注解之后,表示 Mockito 会帮我们创建一个假的 Mock 对象,替换掉 Spring 中已存在的那个真实的 userDao Bean,也就是说,注入进 userService 的 userDao Bean,已经被我们替换成假的 Mock 对象了,所以当我们再次调用 userService 的方法时,会去调用的实际上是 mock userDao Bean 的方法,而不是真实的 userDao Bean。

当我们创建了一个假的 userDao 后,我们需要为这个 mock userDao 自定义方法的返回值,这里有一个公式用法,下面这段代码的意思为,当调用了某个 Mock 对象的方法时,就回传我们想要的自定义结果。

Mockito.when( 对象.方法名() ).thenReturn( 自定义结果 )

代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest
publicclass UserServiceTest {
    
    @Autowired
    private UserService userService;
    
    @MockBean
    private UserDao userDao;

    @Test
    public void getUserById() throws Exception {
        // 定义当调用mock userDao的getUserById()方法,并且参数为3时,就返回id为200、name为I'm mock3的user对象
        Mockito.when(userDao.getUserById(3)).thenReturn(new User(200, "Aritisan"));
        
        // 返回的会是名字为I'm mock 3的user对象
        User user = userService.getUserById(1);

        Assert.assertNotNull(user);
        Assert.assertEquals(user.getId(), new Integer(200));
        Assert.assertEquals(user.getName(), "Aritisan");
    }
}

Mockito 除了最基本的 Mockito.when( 对象.方法名() ).thenReturn( 自定义结果 ),还提供了其他用法让我们使用。

thenReturn

当使用任何整数值调用 userService 的 getUserById() 方法时,就回传一个名字为Aritisan的 User 对象。

Mockito.when(userService.getUserById(Mockito.anyInt())).thenReturn(new User(3, "Aritisan"));
User user1 = userService.getUserById(3); // 回传的user的名字为Aritisan
User user2 = userService.getUserById(200); // 回传的user的名字也为Aritisan

限制只有当参数的数字是 3 时,才会回传名字为 Aritisan 的 user 对象。

Mockito.when(userService.getUserById(3)).thenReturn(new User(3, "Aritisan"));
User user1 = userService.getUserById(3); // 回传的user的名字为Aritisan
User user2 = userService.getUserById(200); // 回传的user为null

当调用 userService 的 insertUser() 方法时,不管传进来的 user 是什么,都回传 100。

Mockito.when(userService.insertUser(Mockito.any(User.class))).thenReturn(100);
Integer i = userService.insertUser(new User()); //会返回100

thenThrow

当调用 userService 的 getUserById() 时的参数是 9 时,抛出一个 RuntimeException。

Mockito.when(userService.getUserById(9)).thenThrow(new RuntimeException("mock throw exception"));
User user = userService.getUserById(9); //会抛出一个RuntimeException

如果方法没有返回值的话(即是方法定义为 public void myMethod() {…}),要改用 doThrow() 抛出 Exception。

Mockito.doThrow(new RuntimeException("mock throw  exception")).when(userService).print();
userService.print(); //会抛出一个RuntimeException

verify

检查调用 userService 的 getUserById()、且参数为3的次数是否为1次。

验证调用顺序,验证 userService 是否先调用 getUserById() 两次,并且第一次的参数是 3、第二次的参数是 5,然后才调用insertUser() 方法。

InOrder inOrder = Mockito.inOrder(userService);
inOrder.verify(userService).getUserById(3);
inOrder.verify(userService).getUserById(5);
inOrder.verify(userService).insertUser(Mockito.any(User.class));

Mockito 注意事项

上述就是 Mockito 的 Mock 对象使用方法,不过当使用 Mockito 在 Mock 对象时,有一些限制需要遵守:

  • 不能 Mock 静态方法
  • 不能 Mock private 方法
  • 不能 Mock final class

因此在写代码时,需要做良好的功能拆分,才能够使用 Mockito 的 Mock 技术,帮助我们降低测试时 Bean 的耦合度。

到此这篇关于SpringBoot中Mockito单元测试入门的文章就介绍到这了,更多相关SpringBoot Mockito单元测试 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Cloud OAuth2 实现用户认证及单点登录的示例代码

    Spring Cloud OAuth2 实现用户认证及单点登录的示例代码

    这篇文章主要介绍了Spring Cloud OAuth2 实现用户认证及单点登录的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • Java TreeSet类的简单理解和使用

    Java TreeSet类的简单理解和使用

    这篇文章主要介绍了Java TreeSet类的简单理解和使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • 一文彻底搞定Java中常用集合的排序方法

    一文彻底搞定Java中常用集合的排序方法

    在某些特殊的场景下我们需要在Java程序中对List集合进行排序操作,下面这篇文章主要给大家介绍了关于Java中常用集合的排序方法的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • Idea中添加Maven项目支持scala的详细步骤

    Idea中添加Maven项目支持scala的详细步骤

    这篇文章主要介绍了Idea中添加Maven项目支持scala,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • @Schedule 如何解决定时任务推迟执行

    @Schedule 如何解决定时任务推迟执行

    这篇文章主要介绍了@Schedule 如何解决定时任务推迟执行问题。具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • java实现屏幕共享功能实例分析

    java实现屏幕共享功能实例分析

    这篇文章主要介绍了java实现屏幕共享功能的方法,以实例形式分析了屏幕共享功能的客户端与服务端的详细实现方法,是非常具有实用价值的技巧,需要的朋友可以参考下
    2014-12-12
  • SpringBoot解决mysql连接8小时问题

    SpringBoot解决mysql连接8小时问题

    服务连接mysql数据库,8小时没有数据库的操作时候,数据库会主动断开连接释放资源,本文就详细的介绍一下解决方法,感兴趣的可以了解一下
    2023-08-08
  • Java 异步回调机制实例分析

    Java 异步回调机制实例分析

    这篇文章主要介绍了Java 异步回调机制实例解析的相关资料,需要的朋友可以参考下
    2017-02-02
  • Java网络编程三要素及通信程序详解

    Java网络编程三要素及通信程序详解

    这篇文章主要介绍了Java网络编程三要素及通信程序详解,Java网络编程是在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以进行数据交换,需要的朋友可以参考下
    2023-07-07
  • RocketMQ源码分析之Broker过期消息清理机制

    RocketMQ源码分析之Broker过期消息清理机制

    这篇文章主要为大家介绍了RocketMQ源码分析之Broker过期消息清理机制示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05

最新评论