继续我们的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方法来打印请求和应答。
本文分享自微信公众号 - 软件测试那些事(antony-not-available),作者:风月同天测试人
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2020-12-04
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句