您好,我是码农飞哥,感谢您阅读本文!如果此文对您有所帮助,请毫不犹豫的一键三连吧!本文主要介绍在SpringMVC框架整合Junit框架进行单元测试。闲话少述,让我们直入主题。
软件 | 版本 |
---|---|
spring-webmvc | 4.3.6.RELEASE |
spring-test | 4.3.6.RELEASE |
junit | 4.12 |
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring.version}version>
<scope>testscope>
dependency>
如上,引入了4个依赖,其中:
test
则指明了该依赖的作用范围是test阶段。@WebAppConfiguration
等注解。@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("file:src/test/java/spring-config.xml")
@ActiveProfiles("dev")
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public abstract class BaseControllerTest {
protected MockMvc mvc;
@Autowired
private WebApplicationContext context;
//获取系统上下文
protected WebApplicationContext getCtx() {
return this.context;
}
//初始化方法
@Before
public void setup() throws SQLException {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
//封装返回结果
protected String getMockResultStr(MockHttpServletRequestBuilder requestBuilder) {
try {
MvcResult mvcResult = this.mockMvc
.perform(requestBuilder)
.andExpect(status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
return response.getContentAsString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
@RunWith(SpringJUnit4ClassRunner.class)
注解表明使用SpringJUnit4ClassRunner来运行测试用例。@WebAppConfiguration
注解表明使用的ApplicationContext将是WebApplicationContext类型的;value属性指定web应用的根;同时,他必须与 @ContextConfiguration
一同使用。@ContextConfiguration
注解的作用是导入我们需要的配置文件或者类,这里指定了SpringMVC的配置文件@ActiveProfiles
注解是指定单元测试连接的环境。@TransactionConfiguration
注解是用与管理spring事务的。MvcResult mvcResult = this.mockMvc
.perform(requestBuilder)
.andExpect(status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
andDo(MockMvcResultHandlers.print())
输出整个响应结果信息,可以在调试的时候使用。RequestBuilder是用来构建请求的。其提供了一个方法buildRequest(ServletContext servletContext) 用于构建MockHttpServletRequest; 其主要有两个子类MockHttpServletRequestBuilder和MockMultipartHttpServletRequestBuilder(文件上传时使用),即用来mock客户端请求需要的所有数据,主要API:
MockHttpServletRequestBuilder get(String urlTemplate, Object… urlVariables): 根据uri模板和uri变量值得到一个GET请求方式的RequestBuilder,如果在controller的方法中method选择的是RequestMethod.GET,那在controllerTest中对应就要使用MockMvcRequestBuilders.get。
post(String urlTemplate, Object… urlVariables):同get类似,但是是POST方法;
通过param 方法来设置请求参数。
get请求的测试就是调用MockMvcRequestBuilders的get方法, 在该方法中传入接口地址。
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/v1/works/lineup/set")
.param("id", "123")
.param("first_flag", String.valueOf(true));
String result = getMockResultStr(requestBuilder);
post请求的测试就是调用MockMvcRequestBuilders的post方法, 在该方法中传入接口地址。
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/v1/blockly/copy")
.param("id", "1211");
success(requestBuilder);
文件上传的测试就是调用MockMvcRequestBuilders的multipart方法, 在该方法中传入接口地址。
File file = new File(RestArmWorksControllerTest.class.getClassLoader().getResource("20201102172053.png").toURI());
MockMultipartFile mockMultipartFile = new MockMultipartFile("file", "20201102172053.png", "", new FileInputStream(file));
MockMultipartHttpServletRequestBuilder servletRequestBuilder = MockMvcRequestBuilders.multipart("/creation/fileUpload.do")
.file(mockMultipartFile);
String result = getMockResultStr(servletRequestBuilder);
String requestJson = JSONObject.toJSONString(folderInfo);
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post("//v1/works/save").contentType(MediaType.APPLICATION_JSON).content(requestJson);
那么,问题来了,如果一个接口的返回结果是视图,那么这个接口的单元测试该如何写呢?比如下面这个接口:
@RequestMapping(value = "/edit")
public String edit(ModelMap model, HttpServletRequest request, HttpServletResponse response) {
Long scriptId = null;
if (StringUtils.isNotBlank(request.getParameter("scriptId"))) {
scriptId = Long.parseLong(request.getParameter("scriptId"));
}
if (scriptId != null) {
MallSuperscript mallSuperscript = superScriptService.getScriptById(scriptId);
model.addAttribute("superScript", mallSuperscript);
}
model.addAttribute("scriptTypeMap", ScriptType.toMap());
logger.info("角标编辑页面返回成功");
return "manage/superScript/edit";
}
这个接口返回的是一个视图,就是名称为edit.jsp页面。它的测试方法可以像下面这样写。
@Test
public void testEdit() throws Exception {
MvcResult mvcResult = mvc
.perform(
get("/manage/tab2/superScript/edit").sessionAttr("adminid", "1111")
.sessionAttr("platformid", 1001L).param("scriptId", "1111"))
.andExpect(status().isOk()).andDo(print()).andReturn();
assertEquals("manage/superScript/edit", mvcResult.getModelAndView().getViewName());
}
通过mvcResult.getModelAndView().getViewName()
获取视图的名称。
上面的那些测试针对的都是Controller层的接口,那么如果要测试一个service层的方法,该如何处理呢?
public class MallMailJobTest extends BaseControllerTest {
private MallMailJob mallMailJob;
@Override
@Before
public void setup() throws SQLException {
super.setup();
mallMailJob = getCtx().getBean(MallMailJob.class);
}
/**
*
* @throws Exception
*/
@Test
public void testExecute() throws Exception {
mallMailJob.execute();
}
被测试的MallMailJob类也可以通过@Autowired
注解直接注入进Spring IOC容器中。拿到被测试类的实例之后就可以直接调用被测试的方法,是不是灰常的简单呀。
本文详细介绍在SpringMVC任何使用Junit框架。首先介绍了如何引入依赖,接着介绍了编写一个测试基类,并且对其中涉及的各个注解做了一个详细说明。最后就是罗列了各种测试情况。