首页 > 技术文章 > SpringBoot单元测试

fengze 2018-01-25 10:50 原文

针对不同的代码层次, 有不同的测试注意事项.

我的理解是:

针对Mapper层或者是Dao层,由于需要跟数据库交互, 写完代码的时候手工执行就好, 由于数据库的数据的不稳定性,不适合用作大量回归测试.

针对Service层的单元测试才是我们通常理解的那种单元测试或者说白盒测试.

针对Controller层的测试,如果Mock了Service层的行为,那这个算是白盒测试,如果没有Mock Service层行为,而是直接调用,我觉得其实已经可以算是集成测试了,这个偏向黑盒测试的范畴,就是我们通常说的API测试.

 

1. 针对Mapper层或者Dao层

如果是有依赖其他Bean对象,可以先写一个专门用来装配Bean的类,并用注解TestConfiguration标注.

当然,这一步也不是必须的,这个只是为了方便在单元测试类中使用@Autowired引入对象.可以在单元测试类中,使用Product product = new Product()代替.

 1 import org.springframework.boot.test.context.TestConfiguration;
 2 import org.springframework.context.annotation.Bean;
 3 
 4 import com.windy.mall.product.bean.Product;
 5 
 6 @TestConfiguration
 7 public class TestBeanConfiguration {
 8 
 9     @Bean
10     public Product createProduct(){
11         return new Product();
12     }
13     
14 }
View Code

 

单元测试类中必须要声明:

(1) @RunWith(Spring.class),表示要在Spring环境中做测试, 于是就可以使用@Autowired等注解了,

(2) @SpringBootTest(classes=TestBeanConfiguration.class),表示可以使用SpringBoot环境了,这样可以用@Autowired注解,把@Mapper注释过的Mapper对象引入.为了引入外部依赖的Bean对象,需要指定classes=TestBeanConfiguration.class.

注意: 之所以要指定classes=TestBeanConfiguration.class,这时因为Product这个类,并没有使用@Component等注解注入IOC容器.

可选:

(3) @Transactional注解来开启事务

(4) @Rollback(true)表示开启回滚数据功能,默认为True.

 1 import org.junit.Assert;
 2 import org.junit.Before;
 3 import org.junit.Test;
 4 import org.junit.runner.RunWith;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.boot.test.context.SpringBootTest;
 7 import org.springframework.test.annotation.Rollback;
 8 import org.springframework.test.context.junit4.SpringRunner;
 9 import org.springframework.transaction.annotation.Transactional;
10 
11 import com.windy.mall.product.bean.Product;
12 import com.windy.mall.product.bean.TestBeanConfiguration;
13 
14 @RunWith(SpringRunner.class)
15 @SpringBootTest(classes=TestBeanConfiguration.class)
16 @Transactional
17 @Rollback(true)
18 public class ProductMapperTest {
19 
20     @Autowired
21     private ProductMapper mapper;
22     
23     @Autowired
24     private Product product;
25     
26     @Before
27     public void setUp(){
28         product.setPname("持续交付");
29         product.setType("书籍");
30         product.setPrice(69d);
31     }
32     
33     @Test
34     public void testAdd() {
35         Assert.assertEquals(Integer.valueOf(1), mapper.add(product));
36     }
37 
38 }
View Code

 

 

2. 针对Service层

由于Service层需要调用Mapper层或者是Dao层,通常需要Mock Mapper对象.这里需要使用到@MockBean注解,Mock Mapper层的行为.

 1 package com.windy.mall.product.service;
 2 
 3 import org.junit.Assert;
 4 import org.junit.Before;
 5 import org.junit.Test;
 6 import org.junit.runner.RunWith;
 7 import org.mockito.BDDMockito;
 8 import org.springframework.beans.factory.annotation.Autowired;
 9 import org.springframework.boot.test.context.SpringBootTest;
10 import org.springframework.boot.test.mock.mockito.MockBean;
11 import org.springframework.test.context.junit4.SpringRunner;
12 
13 import com.windy.mall.product.bean.Product;
14 import com.windy.mall.product.bean.TestBeanConfiguration;
15 import com.windy.mall.product.mapper.ProductMapper;
16 
17 @RunWith(SpringRunner.class)
18 @SpringBootTest(classes = TestBeanConfiguration.class)
19 public class ProductServiceTest {
20 
21     @MockBean
22     private ProductMapper mapper;
23 
24     @Autowired
25     private Product product;
26 
27     @Autowired
28     private ProductService service;
29 
30     @Before
31     public void setUp() {
32         BDDMockito.given(mapper.add(product)).willReturn(1);
33         BDDMockito.given(mapper.add(null)).willReturn(0);
34     }
35 
36     @Test
37     public void testAddService() {
38         Assert.assertEquals(Integer.valueOf(1), service.add(product));
39         Assert.assertEquals(Integer.valueOf(0), service.add(null));
40     }
41 
42 }
View Code

 

3.针对Controller

有两种方法可以做单元测试:

(1) 这里需要用到web环境(webEnvironment=WebEnvironment.RANDOM_PORT).需要用到TestRestTemplate这个对象作为客户方,调用Controller(API)

 1 import org.junit.Assert;
 2 import org.junit.Test;
 3 import org.junit.runner.RunWith;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.boot.test.context.SpringBootTest;
 6 import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
 7 import org.springframework.boot.test.web.client.TestRestTemplate;
 8 import org.springframework.test.context.junit4.SpringRunner;
 9 
10 @RunWith(SpringRunner.class)
11 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
12 public class ProductControllerTest {
13 
14     @Autowired
15     private TestRestTemplate template;
16     
17     @Test
18     public void test() {
19         String body = template.getForObject("/ms/product/1", String.class);
20         Assert.assertEquals("success", body);
21     }
22 
23 }
View Code

 

(2) 如果是使用MockMVC对象来测试,需要开启@AutoConfigureMockMvc注解

 1 import org.junit.Test;
 2 import org.junit.runner.RunWith;
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
 5 import org.springframework.boot.test.context.SpringBootTest;
 6 import org.springframework.test.context.junit4.SpringRunner;
 7 import org.springframework.test.web.servlet.MockMvc;
 8 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
 9 import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
10 
11 @RunWith(SpringRunner.class)
12 @SpringBootTest
13 @AutoConfigureMockMvc
14 public class ProductControllerTest2 {
15 
16     @Autowired
17     private MockMvc mvc;
18 
19     @Test
20     public void test() throws Exception {
21         mvc.perform(MockMvcRequestBuilders.get("/ms/product/1"))
22                 .andExpect(MockMvcResultMatchers.status().isOk())
23                 .andExpect(MockMvcResultMatchers.content().string("success"));
24     }
25 
26 }
View Code

 

推荐阅读