如何使用spring的MockMultipartHttpServletRequest?得到“未找到多部分边界”

问题描述 投票:0回答:7

显然我没有正确使用这个测试装置。 我的 servlet 在 tomcat 中工作得很好,但是当我尝试使用这个模拟时,找不到多部分边界。 “请求被拒绝,因为未找到多部分边界”。

有一个答案here展示了如何使用文本文件来使用它,但是该答案显式设置了边界字符串并将文件嵌入为测试。 我认为我不需要手动使用像 mockrequest.addFile(...)

这样的方法

我在这里没有设置什么或者我怎么做错了?

@org.testng.annotations.Test
public void testDoPost() throws Exception
{
    MockMultipartFile file = new MockMultipartFile("test.zip", "test.zip", "application/zip", MyServletTest.class.getResourceAsStream("/test.zip"));
    MockMultipartHttpServletRequest mockRequest = new MockMultipartHttpServletRequest();
    mockRequest.addFile(file);
    mockRequest.set
    mockRequest.setMethod("POST");
    mockRequest.setParameter("variant", "php");
    mockRequest.setParameter("os", "mac");
    mockRequest.setParameter("version", "3.4");
    MockHttpServletResponse response = new MockHttpServletResponse();
    new MyServletTest().doPost(mockRequest, response);
    //  BOOM !
}

这是例外情况

Caused by: blablah:   the request was rejected because no multipart boundary was found
java unit-testing http servlets spring-test
7个回答
21
投票

你需要设定边界。

这里有关于什么是边界的很好的解释https://stackoverflow.com/a/10932533/2762092

要解决您的问题,请尝试此代码。

    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;

    import org.apache.commons.lang.ArrayUtils;
    import org.springframework.mock.web.MockHttpServletResponse;
    import org.springframework.mock.web.MockMultipartFile;
    import org.springframework.mock.web.MockMultipartHttpServletRequest;


public class FileUploadTest {

    public void testDoPost() throws IOException {
            Path path = Paths.get("c:\\temp\\test.zip");
            byte[] data = Files.readAllBytes(path);
            MockMultipartFile file = new MockMultipartFile("test.zip", "test.zip",
                    "application/zip", data);
            MockMultipartHttpServletRequest mockRequest = new MockMultipartHttpServletRequest();
            String boundary = "q1w2e3r4t5y6u7i8o9";
            mockRequest.setContentType("multipart/form-data; boundary="+boundary);
            mockRequest.setContent(createFileContent(data,boundary,"application/zip","test.zip"));
            mockRequest.addFile(file);
            mockRequest.setMethod("POST");
            mockRequest.setParameter("variant", "php");
            mockRequest.setParameter("os", "mac");
            mockRequest.setParameter("version", "3.4");
            MockHttpServletResponse response = new MockHttpServletResponse();
            new FileUpload().doPost(mockRequest, response);
        }

        public byte[] createFileContent(byte[] data, String boundary, String contentType, String fileName){
            String start = "--" + boundary + "\r\n Content-Disposition: form-data; name=\"file\"; filename=\""+fileName+"\"\r\n"
                     + "Content-type: "+contentType+"\r\n\r\n";;

            String end = "\r\n--" + boundary + "--"; // correction suggested @butfly 
            return ArrayUtils.addAll(start.getBytes(),ArrayUtils.addAll(data,end.getBytes()));
        }
}

3
投票

投票给塞缪尔。尽管花了一天的时间试图让它发挥作用。问题出在:

String end = "--" + boundary + "--";

应该是:

String end = "\r\n--" + boundary + "--";

2
投票

塞缪尔的好答案,但有一个错误:

        String end = "\r\n"+ boundary + "--";

应该是:

        String end = "--"+ boundary + "--";

非常感谢他的工作。


1
投票

您可以使用

MultipartEntityBuilder
创建一个 HttpEntity,如下所示:

HttpEntity httpEntity = MultipartEntityBuilder.create()
        .addTextBody("text-form-field", "Just a line of text.")
        .addTextBody("object-form-field", objectMapper.writeValueAsString(workerMetrics), ContentType.APPLICATION_JSON)
        .addBinaryBody("binary-format", "This would not really be text".getBytes())
        .build();

Spring的后处理

MockMultipartHttpServletRequestBuilder
,添加实体作为内容。复制实体的内容类型将为您设置边界。

mvc.perform(multipart("/upload")
        .with(request -> {
            try {
                request.setContent(httpEntity.getContent().readAllBytes());
                request.setContentType(httpEntity.getContentType().getValue());
                return request;
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        })
).andExpect(status().isAccepted());

0
投票

能够添加多个字段,

   private byte[] createFileContents(String requestId, String date, String image, String invoiceNumber,String imageFile) {

    String requestIdField = "--" + BOUNDARY + "\r\n Content-Disposition: form-data; name=\"" + REQUEST_ID_KEY
            + "\";" + "Content-type: " + CONTENT_TYPE + "\r\n value=\"12345\"" + "\r\n\r\n";
    String requestIdValue = requestId + "\r\n";
    String numberFiledField = "--" + BOUNDARY + "\r\n Content-Disposition: form-data; name=\"" + NUMBER_KEY + "\";"
            + "Content-type: " + CONTENT_TYPE + "\r\n value=\"12345\"" + "\r\n\r\n";
    String invoiceValue = invoiceNumber + "\r\n";
    String dateField = "--" + BOUNDARY + "\r\n Content-Disposition: form-data; name=\"" + DATE_KEY + "\";"
            + "Content-type: " + CONTENT_TYPE + "\r\n value=\"12345\"" + "\r\n\r\n";
    String dateValue = date + "\r\n";
    String imageField = "--" + BOUNDARY + "\r\n Content-Disposition: form-data; name=\"" + IMAGE_KEY
            + "\"; filename=\"" + imageFile + "\"\r\n" + "Content-type: " + CONTENT_TYPE + "\r\n\r\n";
    String imageValue = image + "\r\n";
    String end = "\r\n--" + BOUNDARY + "--";
    return ArrayUtils.addAll((requestIdField + requestIdValue + numberFiledField + invoiceValue + dateField
            + dateValue + imageField + imageValue).getBytes(), ArrayUtils.addAll(data, end.getBytes()));
}

0
投票

我通过模拟 MVC 发送参数和文件来测试 multipart/form-data 的方法如下:

    @Test
void testSendFeedback() throws Exception {
    var builder = MockMvcRequestBuilders.multipart(URL_PATH);

    Path path = Files.createTempFile("test-file", "tmp");
    builder = builder.part(new MockPart("image", path.toFile().getName(), Files.readAllBytes(path)));

    builder.param("field1", "value1")
        .param("fields2", "value2");

    mockMvc.perform(builder.header(HttpHeaders.AUTHORIZATION, YOUR_AUTH_VALUE).contentType(MediaType.MULTIPART_FORM_DATA_VALUE))
        .andDo(print())
        .andExpect(status().isNoContent());
}

0
投票

我解决了必须使用 MultipartBodyBuilder 和 FormHttpMessageConverted 设置边界的问题,RestTemplate 使用 MultipartBodyBuilder 和 FormHttpMessageConverted 将 httpentity 转换为表单数据,以便与 Mockmvc 一起使用。

MultipartBodyBuilder multipartBodyBuilder = new MultipartBodyBuilder();
    multipartBodyBuilder.part("projectId", project.getId());
    multipartBodyBuilder.part("fileName", "sample.txt");
    multipartBodyBuilder.part("format", "txt);
    multipartBodyBuilder.part("file", new ClassPathResource("sample.txt"));

    MultiValueMap<String, HttpEntity<?>> multiValueMap = multipartBodyBuilder.build();


    FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
    HttpOutputMessage outputMessage = new MockHttpOutputMessage();
    formHttpMessageConverter.write(multiValueMap, MediaType.MULTIPART_FORM_DATA, outputMessage);


    mockMvc.perform(MockMvcRequestBuilders.multipart(HttpMethod.POST, "/xxx/xxx").contentType(outputMessage.getHeaders().getContentType()).content(outputMessage.getBody().toString()).with(user())).andExpect(MockMvcResultMatchers.status().isOk());
© www.soinside.com 2019 - 2024. All rights reserved.