使用 Spring MVC Test 对多部分 POST 请求进行单元测试
Posted
技术标签:
【中文标题】使用 Spring MVC Test 对多部分 POST 请求进行单元测试【英文标题】:Using Spring MVC Test to unit test multipart POST request 【发布时间】:2014-03-15 01:48:30 【问题描述】:我有以下用于保存汽车的请求处理程序。我已经验证这在我使用时有效。卷曲。现在我想用 Spring MVC Test 对该方法进行单元测试。我曾尝试使用 fileUploader,但无法使其正常工作。我也没有设法添加 JSON 部分。
我将如何使用 Spring MVC Test 对该方法进行单元测试?我找不到这方面的任何例子。
@RequestMapping(value = "autos", method = RequestMethod.POST)
public ResponseEntity saveAuto(
@RequestPart(value = "data") autoResource,
@RequestParam(value = "files[]", required = false) List<MultipartFile> files)
// ...
我想为我的 auto + 一个或多个文件上传 JSON 表示。
我会给正确答案加 100 赏金!
【问题讨论】:
【参考方案1】:由于不推荐使用 MockMvcRequestBuilders#fileUpload
,因此您需要使用返回 MockMultipartHttpServletRequestBuilder
的 MockMvcRequestBuilders#multipart(String, Object...)
。然后链接一堆file(MockMultipartFile)
调用。
这是一个工作示例。给定一个@Controller
@Controller
public class NewController
@RequestMapping(value = "/upload", method = RequestMethod.POST)
@ResponseBody
public String saveAuto(
@RequestPart(value = "json") JsonPojo pojo,
@RequestParam(value = "some-random") String random,
@RequestParam(value = "data", required = false) List<MultipartFile> files)
System.out.println(random);
System.out.println(pojo.getJson());
for (MultipartFile file : files)
System.out.println(file.getOriginalFilename());
return "success";
static class JsonPojo
private String json;
public String getJson()
return json;
public void setJson(String json)
this.json = json;
还有一个单元测试
@WebAppConfiguration
@ContextConfiguration(classes = WebConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class Example
@Autowired
private WebApplicationContext webApplicationContext;
@Test
public void test() throws Exception
MockMultipartFile firstFile = new MockMultipartFile("data", "filename.txt", "text/plain", "some xml".getBytes());
MockMultipartFile secondFile = new MockMultipartFile("data", "other-file-name.data", "text/plain", "some other type".getBytes());
MockMultipartFile jsonFile = new MockMultipartFile("json", "", "application/json", "\"json\": \"someValue\"".getBytes());
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
mockMvc.perform(MockMvcRequestBuilders.multipart("/upload")
.file(firstFile)
.file(secondFile)
.file(jsonFile)
.param("some-random", "4"))
.andExpect(status().is(200))
.andExpect(content().string("success"));
还有@Configuration
类
@Configuration
@ComponentScan( "test.controllers" )
@EnableWebMvc
public class WebConfig extends WebMvcConfigurationSupport
@Bean
public MultipartResolver multipartResolver()
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
return multipartResolver;
测试应该通过并给你输出
4 // from param
someValue // from json file
filename.txt // from first file
other-file-name.data // from second file
需要注意的是,您发送 JSON 的方式与发送任何其他多部分文件一样,但内容类型不同。
【讨论】:
非常好!对我来说,至关重要的是要理解答案还表明 .file 和 .param 的映射工作方式略有不同。对于 .file,3 个测试文件中的字符串“data”和“json”用于映射到 @RequestPart(value = "json") 或 @RequestParam(value = "data")。在 .param("some-random", "4") 中,"some-random" 将字符串 "4" 映射到 @RequestParam(value = "some-random")。【参考方案2】:MockMvcRequestBuilders.fileUpload
方法已弃用,请改用MockMvcRequestBuilders.multipart
。
这是一个例子:
import static org.hamcrest.CoreMatchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.multipart.MultipartFile;
/**
* Unit test New Controller.
*
*/
@RunWith(SpringRunner.class)
@WebMvcTest(NewController.class)
public class NewControllerTest
private MockMvc mockMvc;
@Autowired
WebApplicationContext wContext;
@MockBean
private NewController newController;
@Before
public void setup()
this.mockMvc = MockMvcBuilders.webAppContextSetup(wContext)
.alwaysDo(MockMvcResultHandlers.print())
.build();
@Test
public void test() throws Exception
// Mock Request
MockMultipartFile jsonFile = new MockMultipartFile("test.json", "", "application/json", "\"key1\": \"value1\"".getBytes());
// Mock Response
NewControllerResponseDto response = new NewControllerDto();
Mockito.when(newController.postV1(Mockito.any(Integer.class), Mockito.any(MultipartFile.class))).thenReturn(response);
mockMvc.perform(MockMvcRequestBuilders.multipart("/fileUpload")
.file("file", jsonFile.getBytes())
.characterEncoding("UTF-8"))
.andExpect(status().isOk());
【讨论】:
【参考方案3】:看看这个取自 Spring MVC 展示的示例,这是指向 source code 的链接:
@RunWith(SpringJUnit4ClassRunner.class)
public class FileUploadControllerTests extends AbstractContextControllerTests
@Test
public void readString() throws Exception
MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes());
webAppContextSetup(this.wac).build()
.perform(fileUpload("/fileupload").file(file))
.andExpect(model().attribute("message", "File 'orig' uploaded successfully"));
【讨论】:
fileUpload
已弃用,取而代之的是 multipart(String, Object...)
。【参考方案4】:
这对我有用,在这里我将一个文件附加到我正在测试的 EmailController。另请查看邮递员截图,了解我如何发布数据。
@WebAppConfiguration
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = EmailControllerBootApplication.class
)
public class SendEmailTest
@Autowired
private WebApplicationContext webApplicationContext;
@Test
public void testSend() throws Exception
String jsonStr = "\"to\": [\"email.address@domain.com\"],\"subject\": "
+ "\"CDM - Spring Boot email service with attachment\","
+ "\"body\": \"Email body will contain test results, with screenshot\"";
Resource fileResource = new ClassPathResource(
"screen-shots/HomePage-attachment.png");
assertNotNull(fileResource);
MockMultipartFile firstFile = new MockMultipartFile(
"attachments",fileResource.getFilename(),
MediaType.MULTIPART_FORM_DATA_VALUE,
fileResource.getInputStream());
assertNotNull(firstFile);
MockMvc mockMvc = MockMvcBuilders.
webAppContextSetup(webApplicationContext).build();
mockMvc.perform(MockMvcRequestBuilders
.multipart("/api/v1/email/send")
.file(firstFile)
.param("data", jsonStr))
.andExpect(status().is(200));
【讨论】:
【参考方案5】:如果您使用的是 Spring4/SpringBoot 1.x,那么值得一提的是,您也可以添加“文本”(json)部分。这可以通过 MockMvcRequestBuilders.fileUpload().file(MockMultipartFile file) 来完成(因为方法.multipart()
在这个版本中不可用):
@Test
public void test() throws Exception
mockMvc.perform(
MockMvcRequestBuilders.fileUpload("/files")
// file-part
.file(makeMultipartFile( "file-part" "some/path/to/file.bin", "application/octet-stream"))
// text part
.file(makeMultipartTextPart("json-part", " \"foo\" : \"bar\" ", "application/json"))
.andExpect(status().isOk())));
private MockMultipartFile(String requestPartName, String filename,
String contentType, String pathOnClassPath)
return new MockMultipartFile(requestPartName, filename,
contentType, readResourceFile(pathOnClasspath);
// make text-part using MockMultipartFile
private MockMultipartFile makeMultipartTextPart(String requestPartName,
String value, String contentType) throws Exception
return new MockMultipartFile(requestPartName, "", contentType,
value.getBytes(Charset.forName("UTF-8")));
private byte[] readResourceFile(String pathOnClassPath) throws Exception
return Files.readAllBytes(Paths.get(Thread.currentThread().getContextClassLoader()
.getResource(pathOnClassPath).toUri()));
【讨论】:
以上是关于使用 Spring MVC Test 对多部分 POST 请求进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章
多对多 Spring MVC mappedBy 引用了一个未知的目标实体属性
使用 spring-test-mvc 自定义测试 http 标头
在 Spring MVC 中使用部分 URL 作为控制器的参数
使用 Spring-Test-MVC 单元测试 Spring-Security - 集成 FilterChain / ServletFilter