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 classBaseJunit
{/*** wac*/@AutowiredprivateWebApplicationContext wac;/*** MockMvc*/
privateMockMvc mockMvc;protectedWebApplicationContext getWac()
{return this.wac;
}protectedMockMvc getMockMvc()
{return this.mockMvc;
}/*** 初始化mocMvc
*
*@see
*/@Beforepublic voidsetUp()
{this.mockMvc = webAppContextSetup(this.wac).build();
}
......
}
@RunWith(SpringJUnit4ClassRunner.class) 指定采用Spring的运行环境
@WebAppConfiguration 用来声明这是一个web测试环境
@ContextConfiguration 用来指定加载项目的配置文件
二、抽出web系统登录方法
public abstract class BaseLoginJunit extendsBaseJunit
{/*** MockMvc*/
privateMockHttpSession session;protectedMockHttpSession getSession()
{returnsession;
}/*** 测试前,初始化系统登录
*
*@see
*/@Beforepublic voidsetUp()
{super.setUp();this.session =(MockHttpSession)getLoginSession();
}/*** 完成登录功能,返回当前登录会话
*
*@returnHttpSession
*@see
*/
privateHttpSession 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();
}returnresult.getRequest().getSession();
}
......
}
三、编写spring控制器测试方法
@FixMethodOrder(MethodSorters.NAME_ASCENDING) //指定按字母顺序执行测试用例
public class ResourceControllerTest extendsBaseLoginJunit
{/*** res id list*/
private static List RES_LIST = new ArrayList<>();/*** 测试 getResource
*
*@see
*/@Testpublic voidtestGetResource()
{
String url= "/xxx/get";
MultiValueMap map = new LinkedMultiValueMap<>();this.setPage(map);
get(url, map);
}/*** 测试 add
*
*@see
*/@Testpublic voidtestAddResource()
{
String url= "/xxx/add";
ResourceBean bean= newResourceBean();
ResourceBean anotherBean= newResourceBean();
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
*/@Testpublic voidtestBupdateResource()
{
String url= "/xxx/update";
ResourceBean bean= newResourceBean();
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
*/@Testpublic voidtestCdelResource()
{
String url= "/xxx/delete";
MultiValueMap map = new LinkedMultiValueMap<>();
map.add("id", RES_LIST.remove(0));
MvcResult result=get(url, map);
assertEquals(AbstractController.STATUS_SUCCESS, getReturnVal(result).getStatus());
}/*** 测试batchDelResource
*
*@see
*/@Testpublic voidtestDbatchDelResource()
{
String url= "/xxx/batchDel";
MultiValueMap map = new LinkedMultiValueMap<>();
StringBuilder params= newStringBuilder();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请求的。
以上是项目中一点记录,各位网友有更好的建议,欢迎拍砖。