在導師公司打工,做了一個版本,技術上雖然沒學到什么新東西,但是至少明白公司開發的各個流程,尤其是在提測階段十分痛苦。一個bug反復出現,不停的修改,不停的調試,十分折騰。總結了一下異常處理沒有放到controller層,log的使用還不夠,另外明白了單元測試的重要性。從前到后找bug實在是太過痛苦,應當用單元測試把bug扼殺在搖籃里。特此總結單元測試的方法和用到的技術,爭取下一個版本做到0bug提測。
包結構規范
單元測試包結構和源碼結構保持一致
命名規范
文件名
被測試文件名+Test
方法名
test+方法名+情況說明
不同單元測試類規范
以下所有的單元測試都要使用assert進行斷言,要注意分支覆蓋率盡可能提高,基層基礎測試類
基礎測試類,用於啟動Springboot環境
@RunWith(SpringRunner.class)
@SpringBootTest
public class MallProductApplicationTests {
@Before
public void setup() {
你的裝載邏輯
}
}
setup方法
每一個測試類都要有一個setup方法並用@Before注解,該方法用於裝載測試時需要的屬性
Controller層
使用MockMvc模擬http請求(見后面教程)
public class TestAttrController extend MallProductApplicationTests{
@Test
public void AttrAddTest() {
使用MockMVC來構造請求
}
}
Service層
Dao層
注意加上注解@RollBack防止數據庫污染,整個類加上@Transactional注解
Mock的使用
mock主要是在某個接口還尚未實現或者難以調用時來產生一個臨時的實現類
MockMVC
MockMVC是Controller層測試時用於構造http請求模擬網絡環境時用到的。由spring-test提供。在json請求場景中使用方法如下
Get請求示例
@WebAppConfiguration
public class MockTest extends GulimallProductApplicationTests {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext wac;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
@Test
public void testMockMvc() throws Exception {
MvcResult result = mockMvc.perform(
MockMvcRequestBuilders.get("/product/category/list"))
.andExpect(MockMvcResultMatchers.jsonPath("$.code")//斷言json返回值
.value(200))
.andReturn();
String contentAsString = result.getResponse().getContentAsString();
System.out.println(contentAsString);
}
}
說明:setup用於向mockMvc傳入當前web環境,可以使用mockmvc的.andExpect來進行斷言,一般在json返回值中使用MockMvcResultMatchers.jsonPath靜態方法斷言json中的某個值是否滿足,也可以通過下面的
result.getResponse().getContentAsString();方法直接得到json字符串做后續處理
post請求示例
@Test
public void testMockMvcPost() throws Exception {
AttrGroupDto attrGroupDto = new AttrGroupDto();
attrGroupDto.setAttrGroupName("a");
attrGroupDto.setCatelogId(1L);
attrGroupDto.setSort(1);
attrGroupDto.setAttrGroupName("bb");
attrGroupDto.setIcon("123123");
MvcResult result = mockMvc.perform(
MockMvcRequestBuilders.post("/product/attrgroup/add")
.content(JSON.toJSONString(attrGroupDto)).contentType(MediaType.APPLICATION_JSON))
.andReturn();
System.out.println(result.getResponse().getContentAsString());
}
使用mockito構造接口
Mockito已經包含在了springboot-test-starter里不需要額外引入
public class MockTest {
AttrDao attrDao;
@Before
public void setup() {
//初始化所有由mokito注解標注的對象
MockitoAnnotations.initMocks(this);
//mock AttrDao接口
attrDao = Mockito.mock(AttrDao.class);
AttrEntity attrEntity = new AttrEntity();
attrEntity.setAttrId(10L);
//定義行為
Mockito.when(attrDao.selectAttrById(1L)).thenReturn(attrEntity);
}
@Test
public void testMock() {
AttrEntity attrEntity = attrDao.selectAttrById(1L);
System.out.println(attrEntity);
}
}
說明:首先需要裝載接口類,然后用Mockito.when().thenReturn方法定義接口中方法的行為即可實現mock調用
也可以使用注解注入
public class MockTest {
@Mock
AttrDao attrDao;
@Before
public void setup() {
//初始化所有由mokito注解標注的對象
MockitoAnnotations.initMocks(this);
//注解注入就不需要這句了
//attrDao = Mockito.mock(AttrDao.class);
AttrEntity attrEntity = new AttrEntity();
attrEntity.setAttrId(10L);
//定義行為
Mockito.when(attrDao.selectAttrById(1L)).thenReturn(attrEntity);
}
@Test
public void testMock() {
AttrEntity attrEntity = attrDao.selectAttrById(1L);
System.out.println(attrEntity);
}
}
Assert的使用
java自帶的關鍵字assert十分僵硬,只能傳入一個boolean值,而且斷言失敗后直接就推出了rollback也不能回滾,因此最好用junit中的Assert類
assertEqual
判斷兩者是否一致
@Test
public void assertEqualTest() {
// 成功
Assert.assertEquals(1L, 1L);
// 失敗
Assert.assertEquals(1L, 2L);
int[] a1 = new int[]{1,2,3};
int[] a2 = new int[]{1,2,3};
int[] a3 = new int[]{2,3,4};
// 成功
Assert.assertArrayEquals(a1, a2);
//失敗
Assert.assertArrayEquals(a1, a3);
}
assertTrue, assertFalse
直接判斷boolean的值
@Test
public void testAssertTrueFalse() {
assertTrue(1 == 1);
assertFalse(1 == 2);
}
assertNull,assertNotNull
就不多說了
assertSame, assertNotSame
判斷兩者對象引用是否相同
assertThat
這個是重點,可以傳入一個hamcrest提供的Matcher接口來進行判斷
Assert.assertThat(obj, Matchers.xxx);