继续我们的MeterSphere之旅。在本小节中,将介绍如何在MeterSphere中创建测试用例。
参考之前文章中介绍的方式,可以找到新建测试用例所对应的后端controller和方法。示例代码如下,
package io.metersphere.track.controller;
@RequestMapping("/test/case")
@RestController
@RequiresRoles(value = {RoleConstants.ADMIN, RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER, RoleConstants.TEST_VIEWER, RoleConstants.ORG_ADMIN}, logical = Logical.OR)
public class TestCaseController {
@Resource
TestCaseService testCaseService;
@PostMapping(value = "/add", consumes = {"multipart/form-data"})
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public void addTestCase(@RequestPart("request") EditTestCaseRequest request, @RequestPart(value = "file") List<MultipartFile> files) {
testCaseService.save(request, files);
}
}
除了URL、POST、角色等等之前已经介绍过的内容之外,这个接口中出现了不同的内容那个。
@PostMapping(value = "/add", consumes = {"multipart/form-data"})
首先是接口类型的注解中,首次出现了consumes = {"multipart/form-data"}这样的属性。这种接口主要是用于上传文件与等服务器交互的操作 。通过在 MeterSpher 在线体验环境: https://demo.metersphere.com/ (账号:demo 密码:P@ssw0rd123..)上的试验操作,可以发现MeterSphere的确允许在新建用例的同时上传用于进一步描述用例的附件,且可以上传多个。如下图所示,
Multipart/form-data是基于Post的请求,不过与普通Post的请求体不同的是它的构造方式 。普通的Post的请求体是简单的name=value组成的列表 , 而Multipart/form-data则是添加了分隔符等内容的构造体。因此,需要进一步来观察这个接口来了解具体的组成。
在接口的入参中,有如下的两个注解,分别表示一种为字符串类型参数,另一种为文件类型参数。
@RequestPart("request") EditTestCaseRequest request, @RequestPart(value = "file")
这说明, 这个Multipart的结构体有两部分组成
所以,这个接口的请求体一部分是和普通post一样的JSON对象,用于表述测试用例自身的属性,另外一部分则是用于上传这个用例的附件。
以下用例用于在MeterSphere中新建一个测试用例。
@Order(3)
@Test
@DisplayName("03用例-新建用例")
public void addTestCase() throws Exception {
testCase.setName("case-"+getRandom());
testCase.setMaintainer("admin");
testCase.setProjectId(project.getId());
testCase.setNodeId(testCaseNode.getId());
testCase.setMethod("manual");
testCase.setPriority("P3");
testCase.setType("functional");
testCase.setNodePath("/"+testCaseNode.getName());
String result= doPostMultipartFormData("/test/case/add",getTestCaseRequest(getEditTestCaseRequest(testCase)),null);
assertThat(result).contains("true");
result=doGet("/test/case/recent/1");
List<TestCase> testCases= JSON.parseArray(String.valueOf(JSON.parseObject(result,ResultHolder.class).getData()),TestCase.class);
assertThat(testCases).isNotEmpty();
testCase=testCases.get(0);
}
上述只是一个简化的示例,主要是展示了如何将一个TestCase实例序列化后塞进Multi-Part类型的请求体中,并通过Post方式发送给后端服务接口。由于附件只是一个测试用例的可选项,请注意此案例并没有上传附件。
从测试用例中可以看到,上述需求可以通过封装一个类似doPost的方法来实现,在这里作为示例的是一个doPostMultipartFormData的方法。它接受URL,以及两个MockMultipartFile类型的入参。
public String doPostMultipartFormData(String url, MockMultipartFile file, MockMultipartFile anotherFile) throws Exception {
return mockMvc.perform(
MockMvcRequestBuilders.multipart(url)
.file(file)
// .file(anotherFile)
.contentType("multipart/form-data")
.session(session)
)
.andDo(print()) //打印出请求和相应的内容
.andExpect(status().isOk()) //返回的状态是200
.andReturn().getResponse().getContentAsString();
}
MockMvc的MockMvcRequestBuilders提供了专门的multipart方法来构建这样的请求。按照之前提到的由于是简化用例,并不提供附件,因此接收附件的第二个MockMultipartFile类型的入参并没有被使用。
接下来问题则是,如何将普通的TestCase序列化之后的字符串转换成这个接口能够接受的MockMultipartFile类型,并命名为"request"。
因此,有如下的一个私有方法用来转换
private MockMultipartFile getTestCaseRequest(EditTestCaseRequest request){
return new MockMultipartFile("request", "", "application/json", JSON.toJSONString(request).getBytes());
}
由于MockMultipartFile只接受二进制的内容,因此需要将TestCase序列化之后再转换成二进制。这里还需要指出一下,"application/json"是必须指定的,不然在后端接口进行解析时会导致TestCase会反序列化失败。
以下是通过
mockMvc.andDo(print())
打印出的请求和响应。
MockHttpServletRequest:
HTTP Method = POST
Request URI = /test/case/add
Parameters = {}
Headers = [Content-Type:"multipart/form-data"]
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = io.metersphere.track.controller.TestCaseController
Method = io.metersphere.track.controller.TestCaseController#addTestCase(EditTestCaseRequest, List)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Type:"application/json"]
Content type = application/json
Body = {"success":true,"message":null,"data":null}
Forwarded URL = null
Redirected URL = null
Cookies = []
可以看到响应中"success":true,表示用例被成功地创建了。比较遗憾的是响应结构体中的data部分并没有返回类似TestCase id之类的信息。为了能够让整个旅程能继续下去,需要得到刚才新建的测试用例ID。因此需要额外通过查询接口来获取到最近一个用例,也就是刚才新建的用例。
result=doGet("/test/case/recent/1");
List<TestCase> testCases= JSON.parseArray(String.valueOf(JSON.parseObject(result,ResultHolder.class).getData()),TestCase.class);
assertThat(testCases).isNotEmpty();
testCase=testCases.get(0);
此处,建议MeterSphere团队能够优化一下这个接口。
”multipart/form-data"类型的请求是基于Post的一种特殊请求,一般用于文件上传,同时支持传输额外的数据。
MockMvc的MockMvcRequestBuilders提供了专门的multipart方法来支持”multipart/form-data"类型的请求。
如果@RequestPart("request")是一个对象,则在构建MockMultipartFile实例时,contentType需要指定为"application/json"。
MockMVC提供了MockMvcResultHandlers.print方法来打印请求和应答。