springboot测试
我们之前的springboot相关文章中,对于一些结果的验证都是通过浏览器作为测试入口来展开,但是实际上我们后端开发人员在写好一个应用程序时,通过现有的测试框架,通过做单元测试对功能做第一轮验收,这个过程中我们能够发现编译错误、一些容易发现的功能性bug和包括各种技术层面的比如数据库连不上等问题。
本篇文章我们将对springboot应用中我们常提到的web层、service服务层和数据库操作层分别做单元测试。
前言&准备
在测试应用程序时,Spring引导提供了许多实用工具和注释。测试支持由两个模块提供:spring-boot-test包含核心项,spring-boot-test-autoconfigure支持测试的自动配置。大多数开发人员使用Spring启动启动器测试“启动器”,它既导入Spring BooST测试模块,又导入JUnit、AssertJ、Hamcrest以及许多其他有用的库。 需要引入测试和其他基础依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <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> <!-- jdbcTemplate --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- druid数据库连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <!-- mysql connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency
1
Dao层单元测试
Dao是应用于数据库交互的代码层,所有与数据库的江湖操作都由上层调用dao层完成。
1.编写dao操作
Dao层实现简单的查询操作:
@Repository public class UserDao { @Autowired JdbcTemplate jdbcTemplate; public User getUserById(Long id) { List<User> list = this.jdbcTemplate.query("select * from User where id = ? limit 1 ",BeanPropertyRowMapper.newInstance(User.class),id); if(null == list || list.isEmpty()) { return null; } return list.get(0); } }
2.数据库操作脚本
在resources目录下添加user.sql脚本:
insert into User values(10,'aeolus',now(),0,28);
3.编写测试代码&验证
在test目录下新建单元测试类DaoTest:
@Transactional @Sql({"/user.sql"}) @RunWith(SpringRunner.class) @SpringBootTest public class DaoTest { @Autowired private UserDao userDao; @Test public void testGetUser() { User user = userDao.getUserById(10L); Assert.assertNotNull(user); Assert.assertEquals("aeolus", user.getName()); Assert.assertSame("不一样呀", 10L, user.getId()); } }
@Transactional测试执行后回滚数据,@Sql({"/user.sql"})‘/’开头表示从classpath根目录开始搜索,没有以此开头默认在测试类所在包下。也可使用classpath:、file:、http: 开头,@Runwith是JUnit标准的一个注解,Spring的单元测试都用SpringRunner.class,@SpringBootTest用于Springboot应用测试,默认根据包名逐级往上 寻找应用启动类。 运行单元测试:
执行完成,根据日志打印的结果可以判断出dao操作数据库成功。
2
service层单元测试
Service层是处理业务逻辑的地方。
1.编写service操作
这里service层通过调用dao层实现查询:
@Service public class UserService { @Autowired private UserDao userDao; public User getUserById(Long id) { return this.userDao.getUserById(id); } }
2.编写测试代码&验证
新建serviceTest类:
@Transactional @RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class ServiceTest { @Autowired UserService userService; @Test public void testGetById() { User user = this.userService.getUserById(1L); log.info("query result={}",user); Assert.assertNotNull(user); Assert.assertEquals("Typhoon", user.getName()); } }
运行单元测试:
日志打印了从DB中查询的数据,并且单元测试执行成功。
3
web层单元测试
很多时候我们都是通过启动应用后,通过浏览器访问来验证程序的可行性,但是我们可以通过测试框架使用更简单的方式来测试controller层程序。Spring MVC Test 通过 @WebMvcTest 来完成MVC单元测试。
1.编写controller层代码
controller层调用UserService返回用户名称:
@RestController public class IndexController { @Autowired private UserService userService; @GetMapping("/user/{id}") public String getUser(@PathVariable("id") Long id) { return this.userService.getUserById(id).getName(); } }
2.编写测试代码&验证
@RunWith(SpringRunner.class) @WebMvcTest(IndexController.class) @Slf4j public class IndexTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test public void testGetUser() throws Exception { Long userId = 1L; BDDMockito.given(userService.getUserById(userId)).willReturn(new User(1L,"Typhoon",null,null,null)); this.mockMvc.perform(MockMvcRequestBuilders.get("/user/{id}",userId)) .andExpect(MockMvcResultMatchers.content().string("Typhoon")); } }
@MockBean 用来模拟实现,因为在Spring MVC测试中并不会初始化@Service注解的类,需要自己模拟service实现。
MockMvc的核心方式是 public ResultActions perform(RequestBuilder requestBuilder) ,下面是一些模拟请求示例:
- 模拟GET请求: mockMvc.perform(MockMvcRequestBuilders.get("/user/{id}", userId));
- 模拟Post请求:
mockMvc.perform(MockMvcRequestBuilders.post("uri", parameters));
运行单元测试:
单元测试执行成功。
总结
springboot单元测试还有很多其他的注解和用法,给我们对应用程序的单测带来了极大的方便,如果感兴趣可以一起探讨。