Mockito 结合 Springboot 进行应用测试的方法详解

Spring Boot可以和大部分流行的测试框架协同工作:通过Spring JUnit创建单元测试;生成测试数据初始化数据库用于测试;Spring Boot可以跟BDD(Behavier Driven Development)工具、Cucumber和Spock协同工作,对应用程序进行测试。

在web应用程序中,我们主要是对Service层做单元测试,以前单元测试都是使用 junit4 ,对Controller层做集成测试或者接口测试,对Controller层的测试一般有两种方法:(1)发送http请求;(2)模拟http请求对象。

第一种方法需要配置回归环境,通过修改代码统计的策略来计算覆盖率;第二种方法是比较正规的思路。

Mockito网上相关的文档不是很多,基本都是入门性质的没有更深层次的使用案例,而且Mockito本身功能也在不断的完善,导致写起来比较费劲,好多地方完全靠猜。摸索之下算是完成了,把踩过的坑记录一下,万一有人需要呢。

下面我将演示如何用Mock对象测试Service、Controller层的代码。

引入相关jar

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

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

项目使用的是 springboot2.4.0。

spring-boot-starter-test 中包含 junit5 和Mockito 相关jar。无需额外引入。

如果想使用 junit4,可以将springboot版本降低,junit4 与 junit5 在一些注解和方法上有区别,比如注解的引入目录不同,一些方法进行了优化,有兴趣可以查阅相关资料,这里就不再赘述。

下面代码是 junit5 使用样式。

项目目录结构如下

Controller类

@RestController
@RequestMapping("/api/v1")
public class UserController {

  @Autowired
  UserService userService;

  @GetMapping("user/{userId}")
  public User say(@PathVariable("userId") Long id) {
    return userService.getUser(id);
  }

  @PostMapping("user/edit")
  public User edit(@RequestBody User user) {
    return userService.edit(user);
  }
}

Service 实现类

@Service
public class UserServiceImpl implements UserService {

  @Autowired
  UserDao userDao;

  @Override
  public User getUser(Long id) {
    return userDao.getUser(id);
  }

  @Override
  public User edit(User user) {
    return userDao.edit(user);
  }
}

Dao 接口

public interface UserDao {
  User getUser(Long id);
  User edit(User user);
}

User 类

public class User {
  private Long id;
  private String name;  private String desc;
  get()...  set()...  toString()...
}

UserDao 是一个接口,没有任何的相关实现。所以对该接口进行mock。测试代码如下

package com.mmling.mockitodemo;import com.mmling.mockitodemo.controller.UserController;import com.mmling.mockitodemo.dao.UserDao;import com.mmling.mockitodemo.entity.User;import com.mmling.mockitodemo.service.UserService;import org.junit.jupiter.api.BeforeEach;import org.junit.jupiter.api.Test;import org.junit.jupiter.api.extension.ExtendWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.boot.test.mock.mockito.MockBean;import org.springframework.http.MediaType;import org.springframework.test.context.junit.jupiter.SpringExtension;import org.springframework.test.web.servlet.MockMvc;import org.springframework.test.web.servlet.ResultActions;import org.springframework.test.web.servlet.setup.MockMvcBuilders;import static org.mockito.ArgumentMatchers.any;import static org.mockito.ArgumentMatchers.anyLong;import static org.mockito.Mockito.times;import static org.mockito.Mockito.verify;import static org.mockito.Mockito.when;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;/** * @author Robert * @date 2020-11-27 14:38 */@ExtendWith(SpringExtension.class)@SpringBootTest(classes = MockitoDemoApplication.class)public class UserBeanTest {  @Autowired  UserController controller;  @Autowired  UserService userService;  @MockBean  //需要mock的bean,会自动注入到调用的对象中  private UserDao userDao;  MockMvc mockMvc;  /**   * 测试 service 层   */  @Test  public void test() {    // 定义未实现的 service 返回    when(userDao.getUser(anyLong())).thenReturn(new User(anyLong(), "张三", "路人"));    System.out.println(userService.getUser(12L).toString());    verify(userDao, times(1)).getUser(anyLong());  }  /**   * 测试 controller 时,需要构建 mvc 环境   */  @BeforeEach  public void setup() {    //构建mvc环境    mockMvc = MockMvcBuilders.standaloneSetup(controller).build();  }  /**   * .perform() : 执行一个MockMvcRequestBuilders的请求;MockMvcRequestBuilders有.get()、.post()、.put()、.delete()等请求。   * .andDo() : 添加一个MockMvcResultHandlers结果处理器,可以用于打印结果输出(MockMvcResultHandlers.print())。   * .andExpect : 添加MockMvcResultMatchers验证规则,验证执行结果是否正确。   */  @Test  public void testGetUser() throws Exception {    // 定义未实现的 service 返回    when(userDao.getUser(anyLong())).thenReturn(new User(12L, "张三", "路人"));    //模拟接口调用    ResultActions perform = this.mockMvc.perform(get("/api/v1/user/12"));    //对接口响应进行验证    perform.andExpect(status().isOk())        .andExpect(content().json("{id:12,name:张三,desc:路人}")); // 可以不用写成转义后的json格式    System.out.println(perform.andReturn().getResponse().getContentAsString());  }  @Test  public void testEditUser() throws Exception {    // 定义未实现的 service 返回    when(userDao.edit(any(User.class))).thenReturn(new User(12L, "张三", "路人"));    //模拟接口调用    ResultActions perform = this.mockMvc.perform(post("/api/v1/user/edit")        .contentType(MediaType.APPLICATION_JSON)        .content("{\"id\":12,\"name\":\"张三\",\"desc\":\"路人\"}"));  // 必须写成转义后的json格式,否则没法转换    //对接口响应进行验证    perform.andExpect(status().isOk())        .andExpect(content().json("{id:12,name:张三,desc:路人}")); // 可以不用写成转义后的json格式    System.out.println(perform.andReturn().getResponse().getContentAsString());  }}

 注意:

  1.由于这是Spring Boot的测试,因此我们可通过@Autowired注解织入任何由Spring管理的对象,或者是通过@Value设置指定的环境变量的值。

  2.每个测试用例用@Test注解修饰。

  3.第一个测试用中展示了如何测试 Service 层代码

  4.第二个第三个测试用例中展示了如何通过MockMvc对象实现对RESTful URL接口订单查询的测试。Spring测试框架提供MockMvc对象,可以在不需要客户端-服务端请求的情况下进行MVC测试,完全在服务端这边就可以执行Controller的请求,跟启动了测试服务器一样。

  5.测试开始之前需要建立测试环境,setup方法被@Before修饰。通过MockMvcBuilders工具,使用 controller 对象作为参数,创建一个MockMvc对象。

  6.mockMvc 可以链式调用,进行接口调用,并判断状态

//模拟接口调用
ResultActions perform = this.mockMvc.perform(get("/api/v1/user/12"))
        .andExpect(status().isOk())
        .andExpect(content().json("{id:12,name:张三,desc:路人}")); // 可以不用写成转义后的json格式

  7. content().json() 会对结果进行处理,所以判断的无需转义,但this.mockMvc.perform(post("/api/v1/user/edit").contentType(MediaType.APPLICATION_JSON).content() 中的json是需要手动转义的。

到此这篇关于Mockito 结合 Springboot 进行应用测试的方法详解的文章就介绍到这了,更多相关Mockito 结合 Springboot应用测试内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Springboot Cucumber测试配置介绍详解

    目前Spring-boot成为了java开发的主流框架,Cucumber作为一款支持dsl的自动化测试工具,很适合用户编写DSL优化过的单元测试等测试用例.本文将讲解如何在SpringBoot中配置Cucumber进行自动化测试. 目录结构如下: gradle相关配置如下所示: testCompile('org.springframework.boot:spring-boot-starter-test', "info.cukes:cucumber-jvm:1.1.8", "i

  • Spring Boot单元测试中使用mockito框架mock掉整个RedisTemplate的示例

    概述 当我们使用单元测试来验证应用程序代码时,如果代码中需要访问Redis,那么为了保证单元测试不依赖Redis,需要将整个Redis mock掉.在Spring Boot中结合mockito很容易做到这一点,如下代码: import org.mockito.Mockito; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration

  • 如何设置Spring Boot测试时的日志级别

    1.概览 该教程中,我将向你展示:如何在测试时设置spring boot 日志级别.虽然我们可以在测试通过时忽略日志,但是如果需要诊断失败的测试,选择正确的日志级别是非常重要的. 2.日志级别的重要性 正确设置日志级别可以节省我们许多时间. 举例来说,如果测试在CI服务器上失败,但在开发服务器上时却通过了.我们将无法诊断失败的测试,除非有足够的日志输出. 为了获取正确数量的详细信息,我们可以微调应用程序的日志级别,如果发现某个java包对我们的测试更加重要,可以给它一个更低的日志级别,比如DEB

  • springboot使用单元测试实战

    前言 springboot提供了 spirng-boot-starter-test 以供开发者使用单元测试,在引入 spring-boot-starter-test 依赖后: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope>

  • SpringBoot Controller Post接口单元测试示例

    概述 在日常的开发中,我们一般会定义一个service层,用于实现业务逻辑,并且针对service层会有与之对应的齐全的覆盖率高的单元测试.而对于controller层,一般不怎么做单元测试,因为主要的核心业务逻辑都在service层里,controller层只是做转发,调用service层接口而已.但是还是建议使用单元测试简单的将controller的方法跑一下,看看转发和数据转换的代码是否能正常工作. 在Spring Boot里对controller层进行单元测试非常简单,只需要几个注解和一

  • Mockito 结合 Springboot 进行应用测试的方法详解

    Spring Boot可以和大部分流行的测试框架协同工作:通过Spring JUnit创建单元测试:生成测试数据初始化数据库用于测试:Spring Boot可以跟BDD(Behavier Driven Development)工具.Cucumber和Spock协同工作,对应用程序进行测试. 在web应用程序中,我们主要是对Service层做单元测试,以前单元测试都是使用 junit4 ,对Controller层做集成测试或者接口测试,对Controller层的测试一般有两种方法:(1)发送htt

  • SpringBoot进行参数校验的方法详解

    目录 介绍 1.SpringBoot中集成参数校验 1.1引入依赖 1.2定义参数实体类 1.3定义校验类进行测试 1.4打开接口文档模拟提交数据 2.参数异常加入全局异常处理器 3.自定义参数校验 3.1创建自定义注解 3.2自定义校验逻辑 3.3在字段上增加注解 3.4体验效果 4.分组校验 4.1定义分组接口 4.2在模型中给参数分配分组 4.3体现效果 介绍 在日常的接口开发中,为了防止非法参数对业务造成影响,经常需要对接口的参数进行校验,例如登录的时候需要校验用户名和密码是否为空,添加

  • SpringBoot设置动态定时任务的方法详解

    之前写过文章记录怎么在SpringBoot项目中简单使用定时任务,不过由于要借助cron表达式且都提前定义好放在配置文件里,不能在项目运行中动态修改任务执行时间,实在不太灵活. 经过网上搜索学习后,特此记录如何在SpringBoot项目中实现动态定时任务. 因为只是一个demo,所以只引入了需要的依赖: <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <ar

  • SpringBoot实现自定义事件的方法详解

    目录 简介 步骤1:自定义事件 步骤2:自定义监听器 方案1:ApplicationListener 方案2:SmartApplicationListener 步骤3:注册监听器 法1:@Component(适用于所有监听器) 法2:application.yml中添加配置 法3:启动类中注册 步骤4:发布事件 法1:注入ApplicationContext,调用其publishEvent方法 法2:启动类中发布 简介 说明 本文用实例来介绍如何在SpringBoot中自定义事件来使用观察者模式

  • SpringBoot导入导出数据实现方法详解

    今天给大家带来的是一个 SpringBoot导入导出数据 首先我们先创建项目 注意:创建SpringBoot项目时一定要联网不然会报错 项目创建好后我们首先对 application.yml 进行编译 server:  port: 8081# mysqlspring:  datasource:    driver-class-name: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://127.0.0.1:3306/dvd?characterEncodi

  • springboot命令行启动的方法详解

    springboot命令行启动 创建的springboot项目想看看效果,不想打开idea等开发工具,使用直接使用命令行启动. maven的命令启动 需要将 jdk的bin目录和maven的bin目录添加到环境变量path中,若是没有,mvn就要用在maven的bin环境中的全路径 若是没有添加环境变量 mvn就要是E:\software\apache-maven-3.3.9\bin\mvn(安装路径\bin\mvn) java就要是C:\software\jdk\bin\java.exe(安装

  • SpringBoot实现整合微信支付方法详解

    目录 1.准备工作 1.1 数据库表 1.2 实体类 1.3 导入依赖 1.4 配置文件 1.5 创建读取微信支付相关信息的工具类 1.6 其他工具类 2.生成订单 2.1 远程调用用户模块和课程模块 2.2 远程调用方法的实现 2.3 根据课程id和用户id生成订单 3.查询订单信息 3.1 controller层 3.2 service层 4.生成微信支付的二维码 4.1 controller层 4.2 service层 5.查询订单支付状态 5.1 controller层 5.2 serv

  • SpringBoot中获取profile的方法详解

    目录 spring boot与profile 静态获取方式 autowire ProfileConfig spring boot与profile spring boot 的项目中不再使用xml的方式进行配置,并且,它还遵循着约定大于配置. 静态获取方式 静态工具类获取当前项目的profile环境. import org.springframework.beans.BeansException; import org.springframework.context.ApplicationConte

  • SpringBoot统一返回格式的方法详解

    目录 前言 1. 直接返回结果 2. 约定返回格式 3. 返回统一格式结果 4. 切片封装统一格式 编写注解 编写ControllerAdvice 见证奇迹的时刻到了 5. 自定义返回格式 场景1:返回成功时code为200 场景2:自定义返回格式 前言 目前很多项目都是前后端分离,前后端会事先约定好返回格式.那么后端如何做,才能优雅的返回统一格式呢,接下来,请大家跟着我,一步步来实现. 1. 直接返回结果 先看一下最基本的例子,直接将结果原封不动返回: @Data @AllArgsConstr

  • SpringBoot中使用监听器的方法详解

    目录 1.监听器 2.SpringBoot中监听器的使用 2.1监听Servlet上下文对象 2.2监听HTTP会话Session对象 总结 1.监听器 web监听器是一张Servlet中特殊的类,它们能帮助开发者监听web中特定的事件,比如ServletContext,HttpSession,ServletRequest的创建和销毁:变量的创建.销毁.和修改等.可以在某些动作前后增加处理,实现监控 2.SpringBoot中监听器的使用 web监听器的使用场景很多,比如监听servlet上下文

随机推荐