單元測試,從必定程度上能夠看出一個同窗達到的層次。但又不徹底是,有時可能只是一個思考方式的轉變。單元測試有很是多的工具供選擇,在java中,junit無疑是比較經常使用的。本文列出,junit在spring中的使用樣例,供參考。java
1:單元測試主要方式web
這裏僅說咱們經常使用的單元測試的場景,或者是我本身經常使用的場景,主要分爲4大類:spring
1. 對外提供的接口級別的測試,如rest-api, 主要用於保證對外提供的接口符合預期, 而非等到別人調用時才發現異常; json
2. serivce 級別的單元測試, 主要用於保證service功能正常;api
3. 靜態方法的測試, 主要用於測試一些工具類符合預期,這類測試通常比較簡單;springboot
4. mock接口實現測試, 這類測試每每最複雜, 通常是爲測試複雜場景, 但又要保證影響因素單一, 保證測試的有效性, 要求既要mock得少也要求mock得合適, 最難;mvc
通常還有對環境初始化時的運行,和結束測試時的清理工做,即setup() 和teardow(). 在junit中就體現爲兩個註解:@Before 和 @After 。app
實際上,除了最後一種測試是比較體系化和完備的以外,前幾種也許都不是那麼細緻,至少通常測試不到某個很小的點上,或者說場景不一致。api,service通常會涉及到複雜的外部系統調用,一是依賴多二是速度慢,而儘可能保持本地化測試中一個最佳實踐。但記住一點,單元測試應該基於行爲,而非基於實現。框架
2. springmvc 的單元測試樣例ide
這裏主要說的是低版本的springmvc, 裏面依賴還比較原始, 因此須要單獨講講。其依賴包可以下參考:
junit junit 4.12 test org.hamcrest hamcrest-core 1.3 org.hamcrest hamcrest-library 1.3 org.mockito mockito-all 1.9.5 test
測試用例樣例以下:(主要注意必要時引用 servlet的配置就行,不然可能找不到對應的controller)
@RunWith(SpringJUnit4Cla***unner.class)@WebAppConfiguration@ContextConfiguration({"classpath:applicationContext.xml", "classpath:applicationContext-servlet.xml"})public class SpringMvcTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void before() throws Exception { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } // 對外提供的接口級別的測試 @Before @After @Test public void tesaDataAddKeyword() throws Exception { TestObj tobj; MvcResult mvcResult; String responseResult; JSONObject resultObj; tobj = new TestObj(); tobj.setXX(302L); mvcResult = mockMvc.perform( MockMvcRequestBuilders.post("/test/add") .contentType("application/json") .characterEncoding("utf-8") .content(JSONObject.toJSONString(tobj))) .andExpect(MockMvcResultMatchers.status().is(200)) .andReturn(); responseResult = mvcResult.getResponse().getContentAsString(); System.out.println("接口返回結果:" + responseResult); resultObj = JSONObject.parseObject(responseResult); Assert.assertNotNull("響應結果爲空", resultObj); Assert.assertThat("正常插入失敗", resultObj.getInteger("status"), is(1)); } @Resource private TestService testService; // serivce 級別的單元測試 @Test public void testPureKeyword() { TestObj tObj = new TestObj(); tObj.setXXX(302L); try { testService.checkKeyWord(tObj); } catch (BizException e) { Assert.assertEquals("錯誤碼返回不正確", 4001021, e.getErrCode()); } } // 靜態方法的測試 @Test public void testUiExtract() { String ruleEL; ParsedClause parsedClause; ruleEL = "ui_extract($123, 'md') = '02-01'"; parsedClause = SyntaxParser.parse(ruleEL); Assert.assertEquals("數量解析不正確", 1, parsedClause.getLabelIdMapping().size()); Assert.assertEquals("解析UPP結果不正確", "string.substring($123 , 5, 10) = '02-01'", parsedClause.translateTo(DialectTypeEnum.ES)); Assert.assertEquals("解析結果不正確", "substr($123 , 5, 5) = '02-01'", parsedClause.translateTo(DialectTypeEnum.HIVE)); } // mock接口實現測試 @Test public void testMockInterface() { List mockList = Mockito.mock(List.class); mockList.add("1"); // 返回null,說明並無調用真正的方法 Assert.assertNull("mock沒有返回null", mockList.get(0)); Mockito.when(mockList.size()).thenReturn(100);//stub // size() method was stubbed,返回100 Assert.assertThat("mock.size未返回預期值", mockList.size(), is(100)); //test for Spy List list = new LinkedList(); List spy = Mockito.spy(list); //optionally, you can stub out some methods: Mockito.when(spy.size()).thenReturn(100); //using the spy calls real methods spy.add("one"); spy.add("two"); //prints "one" - the first element of a list System.out.println(spy.get(0)); //size() method was stubbed - 100 is printed System.out.println(spy.size()); } // 預期發生異常的場景測試 @Test(expected = BizException.class) public void testMethodThrow() { SyntaxParser.parse(null); } }
即對上面4種場景的簡單實現樣例。
3. springboot的單元測試樣例
springboot爲咱們省去了許多的依賴問題,因此不會很麻煩。只需引入 test 包,其餘相應依賴就下來了。並且通常都是demo代碼裏默認帶有的依賴:
org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine
其使用樣例則也會更簡單,一個註解搞定了。
@RunWith(SpringRunner.class)@SpringBootTest@AutoConfigureMockMvcpublic class DemoBatchDataControllerTest { @Autowired private MockMvc mockMvc; @Test public void testApi1() throws Exception { MvcResult result = mockMvc.perform(get("/demo/test1")) .andExpect(status().isOk()) .andReturn(); Assert.assertThat("結果不正確", result.getResponse().getContentAsString(), containsString("ok")); } // 其餘同springmvc }
可見springboot確實簡單了許多。但框架始終只是框架,須要用戶注入靈魂,才能在其上面玩出花樣來。
測試驅動或者測試先行開發,是一種比較好的實踐,可讓咱們少走彎路,且更自信。