小白搞 Spring Boot单元测试

内容是:Spring Boot 中的单元测

前言

何为单元测试

单元测试的目的: 测试当前所写的代码是否是正确的, 例如输入一组数据, 会输出期望的数据; 输入错误数据, 会产生错误异常等. 在单元测试中, 我们需要保证被测系统是独立的(SUT 没有任何的 DOC), 即当被测系统通过测试时, 那么它在任何环境下都是能够正常工作的. 编写单元测试时, 仅仅需要关注单个类就可以了. 而不需要关注例如数据库服务, Web 服务等组件。

背景

进行过JavaWeb开发的同学都了解,在进行后台开发时不仅需要完成系统功能的开发,为了保证系统的健壮性还要同步编写对应的单元测试类。基于Spring Boot开发的项目中的test包用于存放单元测试类,同时也提供了对应的注解来进行单元测试的编写,本文结合Mock对Spring Boot中的单元测试进行总结。

环境:JDK1.8+Spring Bootmockito

单元测试的引入

Spring Boot中引入单元测试只需在pom文件中加入如下依赖,其中提供了JUnit、SpringBoot Test等常见单元测试库。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.0.111-beta</version>
</dependency>

单元测试的创建

每个单元测试类对应项目中的一个程序类,每个单元测试方法对应程序类中的一个方法,为保证所测试方法的正确性,至少需要设计四个以上的测试用例,包含:正确用例、错误用例和边界用例。编写的注释事项如下:

  • 测试类的位置位于项目test包下,包的层级结构与项目相同;
  • 测试类的命名规则通常为 xxxTest.java,其中xxx表示待测试类名;
  • 测试类中方法命名规则为testXxx,其中Xxx表示待测试方法名 ;
  • 测试方法上加上注解 @Test;

话不多说,咱们直接开干。

常用注解

当下是注解盛行时代,我们先来了解一下相关的几个注解。

注解 说明
@RunWith 更改测试运行器 ,   缺省值org.junit.runner.Runner
@Before 初始化方法,执行当前测试类的每个测试方法前执行
@Test 测试方法,在这里可以测试期望异常和超时时间
@Test(timeout = 10000) 超时测试方法,若测试方法未在指定时间内结束则junit自动将其标记为失败
@Transactional 声明式事务管理,用于需数据库事务管理的测试方法
@Rollback(true) 数据库回滚,避免测试数据污染数据库

相关理论和技术点,现在已经铺垫完成,下面,我们使用代码来实现。

代码实现

我们分别做三层的测试:controller、service、dao

Service层测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class UserServiceTest {

@Autowired
    private UserService userService;

/**
     * 测试获取用户
     */
    @Test(timeOut = 300000)
    @Transactional
    public void testGetUser() {
        UserEntity userEntity = userService.findByName("zhangSan");
        Assert.assertNotNull(userEntity);
        Assert.assertEquals("zhangSan", userEntity.getName());
    }
}

是不是很简单呢?

Controller层测

controller层,也可以称之为网络请求测试。对于网络请求进行测试的情形多见于应用的Controller层。Spring测试框架提供MockMvc对象,可以在不需要客户端-服务端请求的情况下进行Web测试.

测试开始之前需要建立测试环境,setup方法被@Before修饰。通过MockMvcBuilders工具,创建一个MockMvc对象。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
class UserControllerTest {

@Autowired
    private UserController userController ;
    @Autowired
    private WebApplicationContext context;
    private MockMvc mockMvc;

@Before
    public void setup(){
        mockMvc = MockMvcBuilders.standaloneSetup(userController).build;
    }

/**
     * 获取用户列表
     */
    @Test(timeOut = 300000)
    public void testGetUserList() throws Exception {
        String url = "/user/getUserList";
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get(url))
                .andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
        Assert.assertNotNull(mvcResult);
    }
}

DAO层测试

由于DAO层的方法直接操作数据库,为避免测试数据对数据库造成污染,使用注解@Transactional@Rollback在测试完成后对测试数据进行回滚。

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

@Autowired
    private UserDao userDao;

/**
     * 测试插入数据
     */
    @Test
    @Rollback(value = true)
    @Transactional
    public void testInsert() {
        User userZhang = new User();
        userZhang.setName("zhangSan");
        userZhang.setAge(23);
        userZhang.setGender(0);
        userZhang.setEmail("123@test.com");
        int n = userDao.insert(userZhang);
        Assert.assertEquals(1, n);
    }
}

到此,关于三个层面的测试就已经搞定了,下面我们来看看,如何使用Mockito模拟数据库操作。

使用Mockito模拟数据库操作

前面在介绍web请求测试时使用了Mock技术,该技术常用于被测试模块(方法)依赖于外部系统(web服务、中间件或是数据库)时。

Mock 的中文译为仿制的,模拟的,虚假的。对于测试框架来说,即构造出一个模拟/虚假的对象,使我们的测试能顺利进行下去。

Mockito 是当前最流行的 单元测试 Mock 框架。采用 Mock 框架,我们可以 虚拟 出一个 外部依赖,降低测试 组件 之间的 耦合度,只注重代码的 流程与结果,真正地实现测试目的。

来于网络,侵删

由于web服务或数据库不可达时,可以对其进行Mock,在测试时不需要真实的模块也可完成测试。

常用的Mockito方法如下:

方法 简介
Mockito.mock(classToMock) 模拟对象
Mockito.when(methodCall).thenReturn(value) 参数匹配
Mockito.doReturn(toBeReturned).when(mock).[method] 参数匹配(直接执行不判断)
Mockito.when(methodCall).thenAnswer(answer)) 预期回调接口生成期望值
Mockito.doNothing().when(mock).[method] 不做任何返回

在使用Mockito对DAO层的单元测试进行模拟后,得到的新的单元测试类如下 :

@RunWith(SpringRunner.class)
public class UserDaoTest {
    @MockBean
    private UserDao userDao;

private User userZhang = new User();
    userZhang.setName("zhangSan");
    userZhang.setAge(23);

@Before
    public void setup() {
        Mockito.when(userDao.findByName("zhangSan")).willReturn(userZhang);
        Mockito.when(userDao.findByName("liSi")).willReturn(null);
    }

@Test
    public void testGetUser() {
        Assert.assertEquals(userZhang, userDao.findByName("zhangSan"));
        Assert.assertEquals(null, userDao.findByName("liSi"));
    }
}

关于mockito相关,请参考官网:https://site.mockito.org/

后记

本文重在用代码案例讲解单元测试,篇幅有限,先分享到这里,如有不当之处,敬请谅解指出。

推荐阅读

(0)

相关推荐

  • 收藏!Java编程技巧之单元测试用例编写流程

    温馨提示:本文较长,同学们可收藏后再看 :) 前言 清代杰出思想家章学诚有一句名言:"学必求其心得,业必贵其专精." 意思是:学习上一定要追求心得体会,事业上一定要贵以专注精深.做 ...

  • 单元测试难?来试试这些套路

    阿里妹导读:测试不应该是一门很高大尚的技术,应该是我们技术人的基本功.但现在好像慢慢地,单元测试已经脱离了基本功的范畴.笔者曾经在不同团队中推过单元测试,要求过覆盖率,但发现实施下去很难.后来在不停地 ...

  • Java单元测试技巧之JSON序列化

    一  前言 <论语>中孔子有言:"工欲善其事,必先利其器." 今年7月,作者迎接更大的挑战,接手并维护了几个Java后端项目.在熟悉业务和代码的过程中,快速地对原有项目 ...

  • 一文让你快速上手 Mockito 单元测试框架

    前言 在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用.为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多 ...

  • Spock是什么?它和JUnit,JMock有什么区别?

    这是Spock系列的第一篇文章,整个专辑会介绍Spock的用途,为什么使用Spock?它能给我们带来什么好处?它和JUnit.JMock.Mockito有什么区别?我们平时写单元测试代码的常见问题和痛 ...

  • 牛逼!在IDEA里搞Spring Boot Mybatis反向工程,太爽咯~

    牛逼!在IDEA里搞Spring Boot Mybatis反向工程,太爽咯~

  • Spring Boot 集成 JUnit5,更优雅单元测试!

    为什么使用JUnit5 JUnit4被广泛使用,但是许多场景下使用起来语法较为繁琐,JUnit5中支持lambda表达式,语法简单且代码不冗余. JUnit5易扩展,包容性强,可以接入其他的测试引擎. ...

  • 小白都能看懂的 Spring Boot 入门指南!

    纯洁的微笑 今天 以下文章来源于Java技术指北 ,作者指北君 什么是Spring Boot Spring Boot 是 Spring 开源组织下的一个子项目,也是 Spring 组件一站式解决方案, ...

  • 一行代码搞定Spring Boot反爬虫,防止接口盗刷!

    每日英文 Fate determines who enters your life, your actions decide who stays. 谁走进你的生命,是由命运决定:谁停留在你生命中,却是 ...

  • 一招搞定 Spring Boot 可视化监控!

    一招搞定 Spring Boot 可视化监控!

  • 官方Spring Boot starters整理

    Spring Boot starters Spring Boot 的功能组件(例如 spring-boot-starter-actuator. spring-boot-starter-data-red ...

  • Spring Boot 解决跨域问题的 3 种方案!

    前后端分离大势所趋,跨域问题更是老生常谈,随便用标题去google或百度一下,能搜出一大片解决方案,那么为啥又要写一遍呢,不急往下看.Java面试宝典PDF完整版 问题背景: Same Origin ...

  • Spring Boot快速开发企业级Admin管理后台

    Erupt 可快速的构建管理页面,零前端代码.零CURD.自动建表,仅需单个类文件 + 简洁的注解配置,即可快速开发企业级Admin管理后台! 后台管理系统非常重要,但开发存在一定的痛点,如:开发效率 ...

  • 一个比 Spring Boot 快 44 倍的 Java 框架

    light-java是内置了undertow http服务器的REST微服务轻量Java框架,它比Spring Boot内嵌Tomcat这样流行的微服务平台要快44倍,与Go语言fast-http性能 ...