junit4相對於junit3,基於注解的方式寫單元測試用例,使用過程中方便很多。如下縮寫均是代碼片段,摘錄其中關鍵部分,重要是理解其中知識點。
一、編寫測試用例基類
@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration({"file:src/main/webapp/WEB-INF/applicationContext.xml", "file:src/main/webapp/WEB-INF/spring-servlet.xml", "file:src/main/webapp/WEB-INF/conf/spring-redis.xml", "file:src/main/webapp/WEB-INF/conf/spring-resttemplate.xml"}) public abstract class BaseJunit { /** * wac */ @Autowired private WebApplicationContext wac; /** * MockMvc */ private MockMvc mockMvc; protected WebApplicationContext getWac() { return this.wac; } protected MockMvc getMockMvc() { return this.mockMvc; } /** * 初始化mocMvc * * @see */ @Before public void setUp() { this.mockMvc = webAppContextSetup(this.wac).build(); }
...... }
@RunWith(SpringJUnit4ClassRunner.class) 指定采用Spring的運行環境
@WebAppConfiguration 用來聲明這是一個web測試環境
@ContextConfiguration 用來指定加載項目的配置文件
二、抽出web系統登錄方法
public abstract class BaseLoginJunit extends BaseJunit { /** * MockMvc */ private MockHttpSession session; protected MockHttpSession getSession() { return session; } /** * 測試前,初始化系統登錄 * * @see */ @Before public void setUp() { super.setUp(); this.session = (MockHttpSession)getLoginSession(); } /** * 完成登錄功能,返回當前登錄會話 * * @return HttpSession * @see */ private HttpSession getLoginSession() { String url = "/xxx/login"; String params = "{\"userName\":\"xxx\",\"password\":\"xxx\",\"verifyCode\":\"xxx\"}"; MvcResult result = null; try { result = getMockMvc().perform( MockMvcRequestBuilders.post(url).accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON_UTF8_VALUE).content( params)).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print()).andReturn(); } catch (Exception e) { e.printStackTrace(); } return result.getRequest().getSession(); }
...... }
三、編寫spring控制器測試方法
@FixMethodOrder(MethodSorters.NAME_ASCENDING) // 指定按字母順序執行測試用例 public class ResourceControllerTest extends BaseLoginJunit { /** * res id list */ private static List<String> RES_LIST = new ArrayList<>(); /** * 測試 getResource * * @see */ @Test public void testGetResource() { String url = "/xxx/get"; MultiValueMap<String, String> map = new LinkedMultiValueMap<>(); this.setPage(map); get(url, map); } /** * 測試 add * * @see */ @Test public void testAddResource() { String url = "/xxx/add"; ResourceBean bean = new ResourceBean(); ResourceBean anotherBean = new ResourceBean(); bean.setResName("test res1"); anotherBean.setResName("test res2"); MvcResult result = post(url, JSONObject.toJSONString(bean)); ReturnVal returnVal = this.getReturnVal(result); RES_LIST.add(returnVal.getData().getId()); MvcResult anotherResult = post(url, JSONObject.toJSONString(childBean)); ReturnVal anotherReturnVal = this.getReturnVal(anotherResult); RES_LIST.add(anotherReturnVal.getData().getId()); } /** * 測試updateResource * * @see */ @Test public void testBupdateResource() { String url = "/xxx/update"; ResourceBean bean = new ResourceBean(); bean.setId(RES_LIST.get(0)); bean.setResName("test res1"); MvcResult result = post(url, JSONObject.toJSONString(bean)); assertEquals(AbstractController.STATUS_SUCCESS, getReturnVal(result).getStatus()); } /** * 測試delResource * * @see */ @Test public void testCdelResource() { String url = "/xxx/delete"; MultiValueMap<String, String> map = new LinkedMultiValueMap<>(); map.add("id", RES_LIST.remove(0)); MvcResult result = get(url, map); assertEquals(AbstractController.STATUS_SUCCESS, getReturnVal(result).getStatus()); } /** * 測試batchDelResource * * @see */ @Test public void testDbatchDelResource() { String url = "/xxx/batchDel"; MultiValueMap<String, String> map = new LinkedMultiValueMap<>(); StringBuilder params = new StringBuilder(); for (int i = 0; i < RES_LIST.size(); i++ ) { if (i == RES_LIST.size() - 1) { params.append(RES_LIST.get(i)); } else { params.append(RES_LIST.get(i)).append(","); } } map.add("id", params.toString()); MvcResult result = get(url, map); assertEquals(AbstractController.STATUS_SUCCESS, getReturnVal(result).getStatus()); } }
以上測試用例中,@FixMethodOrder很關鍵,因為增、刪、改、查需要指定測試的順序。MethodSorters.NAME_ASCENDING指定按字母順序執行測試用例,注意test后的第一個字母,按照A、B、C、D來的。在junit中,@FixMethodOrder的值有三種選擇,分別如下:
MethodSorters.DEFAULT:按默認順序,具體怎樣的順序不確定。
MethodSorters.JVM:按JVM得到的方法順序。
MethodSorters.NAME_ASCENDING:按字母順序。
用例中,需要測試用例按指定順序執行,測試時使用MethodSorters.JVM,有解釋說,這個是按照方法中方法的順序執行,實際測試不可行。最終選擇MethodSorters.NAME_ASCENDING按字母指定順序。幾個用例中涉及到數據依賴的問題,在這里,把依賴的數據都放入靜態的RES_LIST中,供各方法共享。
ps:
1、以上使用過程中,使用setUp初始化登錄,而junit中每個test用例執行前,都會調用setUp方法,導致登錄功能頻繁調用,實際上只調用一次就好。這個問題有待解決。不過按以上方法,從模擬登錄,到指定測試流程均可進行,一般的測試都可以滿足。
2、這里描述的只是控制器部分的測試,只是測試http請求的。
以上是項目中一點記錄,各位網友有更好的建議,歡迎拍磚。