Spring - MultipartFileUpload与容器和自定义验证器的集成测试

时间:2016-11-29 15:58:01

标签: java spring unit-testing spring-mvc thymeleaf

问题

我正在尝试编写集成测试,目的是验证文件上传。

正常文件上传按预期工作(文件在满足要求时上传),但测试不执行并引发错误。

Invalid target for Validator [my.package.here.validators.FileContainerValidator#0 bean]: my.package.here.models.FileContainer@7661b5a

作为额外信息,我正在寻找基于注释的解决方案

当前代码库

Thymeleaf文件上传表单:

        <form method="POST" action="#" th:action="@{/upload}" th:object="${fileContainer}"
              enctype="multipart/form-data">
                <input type="file" th:field="*{file}" id="file"/>
            </label>
            <br><br>
            <label for="destination">Destination:</label>
            <input type="text" value="/tmp" id="destination" th:field="*{destination}"/>
            <input type="submit" value="Upload" name="upload" id="upload"/>
       </form>

FileUploadController:

@Controller
public class FileUploadController {

    private final FileStorageService fileStorageService;

    FileContainerValidator fileContainerValidator;

    @Autowired
    public void setDefaultFileContainerValidator(FileContainerValidator validator) {
        this.fileContainerValidator = validator;
    }

    @Autowired
    public FileUploadController(FileStorageService FileStorageService) {
        this.fileStorageService = FileStorageService;
    }

    @GetMapping("/upload")
    public String showTestFileUploadForm(@ModelAttribute Mapping mapping, FileContainer fileContainer, Model model) {
        String path = "ERROR";
        try {
            path = new ClassPathResource("data.csv").getFile().getPath();
        } catch (IOException e) {
            e.printStackTrace();
        }

        model.addAttribute("shortenedFile", new TableConstructor(path, mapping.getContentDelimiter()));
        return "upload";
    }

    @PostMapping("/upload")
    public String uploadFile(@Valid FileContainer fileContainer, BindingResult result) {
        if (result.hasErrors()) {
            for (ObjectError e : result.getAllErrors())
                System.out.println("ERROR: " + e.toString());
            //TODO: Error msg
        } else {
            System.out.println("Fetching file");
            fileStorageService.store(fileContainer);
            //TODO: SUCCESS
        }
        return "redirect:/upload";
    }

    @InitBinder("fileContainer")
    protected void initBinderFileContainer(WebDataBinder binder) {
        binder.setValidator(fileContainerValidator);
    }
}

FileContainer类:

public class FileContainer implements Serializable {
    private MultipartFile file;
    private String destination;

    public FileContainer(MultipartFile file, String destination) {
        Assert.notNull(file, "The file must not be null or empty!");
    }

    //Unused but needed for string
    public FileContainer() {
    }

    public String getDestination() {
        return destination;
    }


    public void setDestination(String destination) {
        this.destination = destination;
    }

    public MultipartFile getFile() {
        return file;
    }

    public void setFile(MultipartFile file) {
        Assert.notNull(file, "The file must not be null or empty!");
        this.file = file;
    }
}

最后但并非最不重要的是,测试:

@RunWith(SpringRunner.class)
@WebMvcTest(FileUploadController.class)
public class FileUploadIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private FileStorageService fileStorageService;

    @MockBean
    private FileContainerValidator fileContainerValidator;

    private MockMultipartFile correctFile =
            new MockMultipartFile("data", "filename.xml", "text/plain", "some xml".getBytes());

    private MockMultipartFile fileWithWrongExtension =
            new MockMultipartFile("data", "filename.txt", "text/plain", "this is a wrong file!".getBytes());

    private String testDestination = "/tmp";

    @Test
    public void uploadMultipartTestFile() throws Exception {
       mockMvc.perform(fileUpload("/upload")
                .file(correctFile)
                .param("destination", testDestination))
                .andExpect(
                        model().attributeExists("fileContainer")
                );
    }
}

1 个答案:

答案 0 :(得分:1)

当在控制器InitBinders的binder.setValidator方法被测试运行器调用时,它会抛出&#34;验证器的目标无效&#34;错误。您可以返回&#34; true&#34;通过对Validator类的supports方法进行存根。还有一件事,你的FileContainer类有属性&#34; file&#34;而在你的MockMultipartFile中,你正在使用&#34; data&#34;。这将导致通过测试上载空文件。

    @Autowired 
    private WebApplicationContext webApplicationContext;

    @Test
    public void uploadMultipartTestFile() throws Exception {
     MockMultipartFile correctFile = new MockMultipartFile("file", "filename.txt", "text/plain", "C:\\temp\\test.txt".getBytes());        
     MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
     when(fileContainerValidator.supports(any(Class.class))).thenReturn(true);
     mockMvc.perform(MockMvcRequestBuilders.fileUpload("/upload")
                .file(correctFile)
                .param("destination", "/tmp"))
                .andExpect(content().string("redirect:/upload")
                 );
    }