使用 TestRestTemplate 进行 Multipart POST 请求的集成测试返回 400
Posted
技术标签:
【中文标题】使用 TestRestTemplate 进行 Multipart POST 请求的集成测试返回 400【英文标题】:Integration test with TestRestTemplate for Multipart POST request returns 400 【发布时间】:2017-09-09 16:04:18 【问题描述】:我知道类似的问题已经出现过几次了,但是按照建议的修复方法并没有解决我的问题。
我有一个带有以下端点的简单控制器:
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<String> singleFileUpload(@RequestParam("file") MultipartFile file)
log.debug("Upload controller - POST: ", file.getOriginalFilename());
// do something
我正在尝试使用 Spring TestRestTemplate
为其编写集成测试,但我所有的尝试都以 400 - Bad Request
结尾(没有日志说明控制台中出了什么问题)。
控制器内部的日志没有被命中,所以在到达那里之前就失败了。
您能否看看我的测试并指出我做错了什么?
@Test
public void testUpload()
// simulate multipartfile upload
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("image.jpg").getFile());
MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<String, Object>();
parameters.add("file", file);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<MultiValueMap<String, Object>>(parameters, headers);
ResponseEntity<String> response = testRestTemplate.exchange(UPLOAD, HttpMethod.POST, entity, String.class, "");
// Expect Ok
assertThat(response.getStatusCode(), is(HttpStatus.OK));
【问题讨论】:
看起来您在测试中设置了 ContentType = MULTIPART_FORM_DATA。但是您的控制器未设置为接收此类请求。尝试使用 consumes = MediaType.MULTIPART_FORM_DATA_VALUE 请发布测试类的其余部分,因为有一些我无法在此处重现的缺失部分 @BrunoLeite 谢谢你的建议。我试过了,但事实并非如此。 你真的用你的响应实体返回一个字符串吗?您是否验证了 400 响应正文中的内容,以防它提供更多详细信息?您是否考虑过使用调试器运行它或实现异常处理程序? 是的,正在返回字符串。它在集成测试之外工作正常。在这个测试中,我发布了。我什至没有得到调试线,所以在它到达控制器主体之前发生了一些事情。 【参考方案1】:我尝试了以下方法:
@Test
public void testUpload()
LinkedMultiValueMap<String, Object> parameters = new LinkedMultiValueMap<String, Object>();
parameters.add("file", new org.springframework.core.io.ClassPathResource("image.jpg"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> entity = new HttpEntity<LinkedMultiValueMap<String, Object>>(parameters, headers);
ResponseEntity<String> response = testRestTemplate.exchange(UPLOAD, HttpMethod.POST, entity, String.class, "");
// Expect Ok
assertThat(response.getStatusCode(), is(HttpStatus.OK));
如您所见,我使用 org.springframework.core.io.ClassPathResource
作为文件的对象,并且效果非常好
希望有用
安杰洛
【讨论】:
首先我不清楚是什么导致了这个问题。多部分控制器是否与java.io.File
不兼容?无论如何,它确实像一个魅力,谢谢。这为我节省了很多工作!
@Smajl 我猜想其余模板能够更好地管理org.springframework.core.it.Resource
实现而不是传递一个简单的java.io.File
我知道这已经很老了,但我能问你,你的“image.jpg”文件在你的项目中的什么位置?
@bot_bot 在我的代码中,图像位于类路径下(如果您使用的是 maven,则在 src/main/resources
中)【参考方案2】:
如果你想使用java.nio.file.Path
,也可以使用FileSystemResource
。
包裹:org.springframework.core.io.FileSystemResource
例如,您可以这样做:
new FileSystemResource(Path.of("src", "test", "resources", "image.jpg"))
完整代码示例:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UploadFilesTest
private final TestRestTemplate template;
@Autowired
public UploadFilesTest(TestRestTemplate template)
this.template = template;
@Test
public void uploadFileTest()
var multipart = new LinkedMultiValueMap<>();
multipart.add("file", file());
final ResponseEntity<String> post = template.postForEntity("/upload", new HttpEntity<>(multipart, headers()), String.class);
assertEquals(HttpStatus.OK, post.getStatusCode());
private HttpHeaders headers()
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
return headers;
private FileSystemResource file()
return new FileSystemResource(Path.of("src", "test", "resources", "image.jpg"));
休息控制器:
@RestController
public class UploadEndpoint
@PostMapping("/upload")
public void uploadFile(@RequestParam("file") MultipartFile file)
System.out.println(file.getSize());
【讨论】:
以上是关于使用 TestRestTemplate 进行 Multipart POST 请求的集成测试返回 400的主要内容,如果未能解决你的问题,请参考以下文章
spring boot使用TestRestTemplate集成测试 RESTful 接口
Spring TestRestTemplate 未正确自动装配
spring boot 测试无法注入 TestRestTemplate 和 MockMvc