針對不一樣的代碼層次, 有不一樣的測試注意事項.web
個人理解是:spring
針對Mapper層或者是Dao層,因爲須要跟數據庫交互, 寫完代碼的時候手工執行就好, 因爲數據庫的數據的不穩定性,不適合用做大量回歸測試.數據庫
針對Service層的單元測試纔是咱們一般理解的那種單元測試或者說白盒測試.mvc
針對Controller層的測試,若是Mock了Service層的行爲,那這個算是白盒測試,若是沒有Mock Service層行爲,而是直接調用,我以爲其實已經能夠算是集成測試了,這個偏向黑盒測試的範疇,就是咱們一般說的API測試.app
1. 針對Mapper層或者Dao層ide
若是是有依賴其餘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 }
單元測試類中必需要聲明:ui
(1) @RunWith(Spring.class),表示要在Spring環境中作測試, 因而就可使用@Autowired等註解了,spa
(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 }
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 }
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 }
(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 }