使用MockMultipartFile测试最大上载文件大小

fab*_*bwu 7 spring spring-mvc spring-test spring-test-mvc spring-boot

我使用Spring Boot创建了一个文件上传服务,并使用Spring Mock Mvc和MockMultipartFile进行测试.我想测试是否在超出最大文件大小时抛出错误.以下测试失败,因为它收到200.

RandomAccessFile f = new RandomAccessFile("t", "rw");
f.setLength(1024 * 1024 * 10);
InputStream is = Channels.newInputStream(f.getChannel());

MockMultipartFile firstFile = new MockMultipartFile("data", "file1.txt", "text/plain", is);

mvc.perform(fileUpload("/files")
    .file(firstFile))
    .andExpect(status().isInternalServerError());
Run Code Online (Sandbox Code Playgroud)

有没有可能测试上传文件的大小?

jny*_*jny 6

根据文档

如果使用length方法返回的文件的当前长度小于newLength参数,则将扩展文件。在这种情况下,未定义文件扩展部分的内容。

尝试以下方法:

byte[] bytes = new byte[1024 * 1024 * 10];
MockMultipartFile firstFile = new MockMultipartFile("data", "file1.txt", "text/plain", bytes);
Run Code Online (Sandbox Code Playgroud)

  • @ wuethrich44:确实如此。我偶然发现了同样的问题,也找不到简单的解决方案。没有查看“ spring-web”的代码(或任何应该处理的代码),我忍不住注意到一些Tomcat代码(* ie *`java)抛出了实际的异常(超出限制)。 .lang.IllegalStateException:org.apache.tomcat.util.http.fileupload.FileUploadBase $ FileSizeLimitExceededException:字段文件超出了其最大允许大小1048576字节。)。因此,也许Spring只是将签出委托给了底层的应用服务器。 (7认同)
  • 这对我不起作用。MockMVC是否可能禁用了文件大小检查? (6认同)
  • @ wuethrich44:由于`MockMvc`集成测试并未真正包含实际的应用服务器... (3认同)
  • @PriiduNeemre好的,当Tomcat处理此错误时,似乎无法在`MockMvc`中进行测试。奇怪的是,@ David Jones在此解决方案上取得了成功... (2认同)
  • David可能正在执行手动大小检查以及/而不是使用Spring属性。 (2认同)

Mor*_*itz 6

无法使用 Spring 的 MockMultipartFile / MockMvc 对此进行测试。原因是错误的根源不在 Spring 本身,而是在底层 Web 服务器(最常见的是 Tomcat)中,正如您在 MaxUploadSizeExceededException 的堆栈跟踪中看到的那样:

org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size of 500000 bytes exceeded; nested exception is org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (1065736) exceeds the configured maximum (500000)
    at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:160)
    at org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:139)
[...]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (1065736) exceeds the configured maximum (500000)
    at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:965)
    at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:310)
    at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:334)
    at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:115)
    at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:156)
    ... 20 more
Run Code Online (Sandbox Code Playgroud)

当使用默认的 MockMvc 并使用@SpringBootTest其默认设置时,不会启动真正的 Web 服务器,因此不会发生错误。

然而,您可以通过提供 来告诉 Spring 启动一个真正的 Web 服务器来进行测试@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT),这将(令人惊讶地)在随机端口上启动一个 Web 服务器。您可以在测试类中使用 访问该端口@LocalServerPort

然后,您可以编写一个测试,对您的测试服务器执行真正的分段上传,而不是伪造的。REST Assured是一个可以执行以下操作的库:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyTest {

    @LocalServerPort
    private int port;

    @Test
    void testMultipartUpload() throws Exception {
        File file = new File("my-file");
        RestAssured.baseURI = "http://localhost/api";
        RestAssured.port = port;
        Response res = given()
                .multiPart("data", file, "text/plain")
                .when().post("/upload");
        ...
    }

}
Run Code Online (Sandbox Code Playgroud)

当您的上传太大时,此测试将显示服务器错误。