小白搞 Spring Boot 单元测试

开发 架构
进行过JavaWeb开发的同学都了解,在进行后台开发时不仅需要完成系统功能的开发,为了保证系统的健壮性还要同步编写对应的单元测试类。

[[420921]]

大家好,我是田维常,今天给大家分享来自于一位小伙的投稿。

内容是:Spring Boot 中的单元测

前言

何为单元测试

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

背景

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

环境:JDK1.8+、Spring Boot、mockito。

单元测试的引入

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

  1. <dependency> 
  2.     <groupId>org.springframework.boot</groupId> 
  3.     <artifactId>spring-boot-starter-test</artifactId> 
  4.     <scope>test</scope> 
  5. </dependency> 
  6. <dependency> 
  7.     <groupId>org.mockito</groupId> 
  8.     <artifactId>mockito-core</artifactId> 
  9.     <version>2.0.111-beta</version> 
  10. </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层测试

  1. @RunWith(SpringRunner.class) 
  2. @SpringBootTest(classes = Application.class) 
  3. public class UserServiceTest { 
  4.  
  5.     @Autowired 
  6.     private UserService userService; 
  7.  
  8.     /** 
  9.      * 测试获取用户 
  10.      */ 
  11.     @Test(timeOut = 300000) 
  12.     @Transactional 
  13.     public void testGetUser() { 
  14.         UserEntity userEntity = userService.findByName("zhangSan"); 
  15.         Assert.assertNotNull(userEntity); 
  16.         Assert.assertEquals("zhangSan", userEntity.getName()); 
  17.     } 

是不是很简单呢?

Controller层测

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

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

  1. @RunWith(SpringRunner.class) 
  2. @SpringBootTest(classes = Application.class) 
  3. class UserControllerTest { 
  4.  
  5.     @Autowired 
  6.     private UserController userController ; 
  7.     @Autowired 
  8.     private WebApplicationContext context; 
  9.     private MockMvc mockMvc; 
  10.  
  11.     @Before 
  12.     public void setup(){ 
  13.         mockMvc = MockMvcBuilders.standaloneSetup(userController).build; 
  14.     } 
  15.  
  16.     /** 
  17.      * 获取用户列表 
  18.      */ 
  19.     @Test(timeOut = 300000) 
  20.     public void testGetUserList() throws Exception { 
  21.         String url = "/user/getUserList"
  22.         MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get(url)) 
  23.                 .andExpect(MockMvcResultMatchers.status().isOk()).andReturn(); 
  24.         Assert.assertNotNull(mvcResult); 
  25.     } 

DAO层测试

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

  1. @RunWith(SpringRunner.class) 
  2. @SpringBootTest 
  3. public class ScoreControllerTestNew { 
  4.  
  5.     @Autowired 
  6.     private UserDao userDao; 
  7.  
  8.     /** 
  9.      * 测试插入数据 
  10.      */ 
  11.     @Test 
  12.     @Rollback(value = true
  13.     @Transactional 
  14.     public void testInsert() { 
  15.         User userZhang = new User(); 
  16.         userZhang.setName("zhangSan"); 
  17.         userZhang.setAge(23); 
  18.         userZhang.setGender(0); 
  19.         userZhang.setEmail("123@test.com"); 
  20.         int n = userDao.insert(userZhang); 
  21.         Assert.assertEquals(1, n); 
  22.     } 

到此,关于三个层面的测试就已经搞定了,下面我们来看看,如何使用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层的单元测试进行模拟后,得到的新的单元测试类如下 :

  1. @RunWith(SpringRunner.class) 
  2. public class UserDaoTest { 
  3.     @MockBean 
  4.     private UserDao userDao; 
  5.  
  6.     private User userZhang = new User(); 
  7.     userZhang.setName("zhangSan"); 
  8.     userZhang.setAge(23); 
  9.  
  10.     @Before 
  11.     public void setup() { 
  12.         Mockito.when(userDao.findByName("zhangSan")).willReturn(userZhang); 
  13.         Mockito.when(userDao.findByName("liSi")).willReturn(null); 
  14.     } 
  15.  
  16.     @Test 
  17.     public void testGetUser() { 
  18.         Assert.assertEquals(userZhang, userDao.findByName("zhangSan")); 
  19.         Assert.assertEquals(null, userDao.findByName("liSi")); 
  20.     } 

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

后记 

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

本文转载自微信公众号「Java后端技术全栈」,可以通过以下二维码关注。转载本文请联系Java后端技术全栈公众号。

 

责任编辑:武晓燕 来源: Java后端技术全栈
相关推荐

2021-01-07 14:06:30

Spring BootJUnit5Java

2023-09-27 23:43:51

单元测试Spring

2013-06-04 09:49:04

Spring单元测试软件测试

2021-08-26 11:00:54

Spring BootJUnit5Java

2017-01-14 23:42:49

单元测试框架软件测试

2017-01-16 12:12:29

单元测试JUnit

2017-01-14 23:26:17

单元测试JUnit测试

2020-07-21 14:40:45

Spring Boot单元测试Java

2020-08-18 08:10:02

单元测试Java

2021-04-23 07:33:10

SpringSecurity单元

2023-07-26 08:58:45

Golang单元测试

2017-03-23 16:02:10

Mock技术单元测试

2011-07-04 18:16:42

单元测试

2020-05-07 17:30:49

开发iOS技术

2021-05-05 11:38:40

TestNGPowerMock单元测试

2011-05-16 16:52:09

单元测试彻底测试

2024-10-16 16:09:32

2022-08-02 08:07:24

单元测试代码重构

2009-09-29 16:21:31

Hibernate单元

2016-09-21 15:35:45

Javascript单元测试
点赞
收藏

51CTO技术栈公众号