Spring - 验证程序不会在集成测试中触发

时间:2016-12-07 11:25:10

标签: java spring validation spring-mvc integration-testing

问题

实际上,这是一种"follow-up" question。我有2个集成测试运行文件上传,测试相应的控制器。不幸的是,在使用我的另一个问题的答案的解决方案后,第二次集成测试应该"失败" (因为文件的扩展名为"错误"因此FileContainerValidator应拒绝该文件)不会失败!验证者甚至没有被召唤。

如何解决问题?

我的代码

FileUploadController

@Controller
public class FileUploadController {

    private final FileStorageService fileStorageService;

    FileContainerValidator fileContainerValidator;

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

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

    @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(Model model, @Valid FileContainer fileContainer, BindingResult result) {
        if (!result.hasErrors()) {
            System.out.println("Fetching file");
            fileStorageService.store(fileContainer);
            //TODO: SUCCESS
            model.addAttribute("success", true);
        }

        return "upload";
    }

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

FileUploadIntegrationTest

@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("file", "filename.xml", "text/plain", "some xml".getBytes());

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

    private String testDestination = "/tmp";

    //THIS ONE WORKS
    @Test
    public void uploadMultipartTestFile() throws Exception {
        when(fileContainerValidator.supports(any(Class.class))).thenReturn(true);
        mockMvc.perform(MockMvcRequestBuilders.fileUpload("/upload")
                .file(correctFile)
                .param("destination", "/tmp"))
                .andExpect(model().attribute("success", true));
    }

    //THIS ONE DOES NOT WORK
    @Test
    public void errorOnUploadFileWithWrongExtension() throws Exception {
      when(fileContainerValidator.supports(any(Class.class))).thenReturn(true);
        mockMvc.perform(MockMvcRequestBuilders.fileUpload("/upload")
                .file(fileWithWrongExtension)
                .param("destination", "/tmp"))
                .andExpect(model().attributeHasFieldErrors("fileContainer.file"));
    }
}

FileContainerValidator

@Component
public class FileContainerValidator implements Validator {
    public boolean supports(Class<?> clazz) {
        return FileContainer.class.equals(clazz);
    }

    @Override
    public void validate(Object obj, Errors errors) {
        FileContainer fileContainer = (FileContainer) obj;
        MultipartFile file = fileContainer.getFile();
        String destination = fileContainer.getDestination();
        if (file != null) {
            if (file.getSize() == 0) {
                errors.rejectValue("file", "missing.file", "The file must not be null or empty!");
            }
            if(file.getOriginalFilename().contains(".")) {
                String extension = file.getOriginalFilename().split("\\.")[1];
                if (!extension.equalsIgnoreCase("xml") && !extension.equalsIgnoreCase("csv")) {
                    errors.rejectValue("file", "extension.file", "The file had the wrong extension!");
                }
            } else {
                errors.rejectValue("file", "extension.file", "The file had the wrong extension!");
            }
        } else {
            errors.rejectValue("file", "missing.file", "The file must not be null or empty!");
        }
        if(destination != null && !destination.isEmpty()){
            if(!destination.matches("([a-zA-Z]:)?(\\/[a-zA-Z0-9_.-]+)+\\/?"))
                errors.rejectValue("destination", "wrong.destination", "The destination is given wrong");
        } else {
            errors.rejectValue("destination", "missing.destination", "The destination is missing");
        }
    }
}

表格(&#34; upload.html&#34;)

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns:th="http://www.thymeleaf.org" lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head th:include="head :: head (pagename='Upload File')"></head>

<body>

<div th:replace="fragments/nav :: nav">&copy; Static</div>
<div class="panel panel-default" id="welcome-panel">
    <div class="panel-heading">
        <h2>Upload File</h2>
    </div>
    <div class="panel-body">
        <div class="alert alert-success" th:if="${success}">File successfully uploaded!</div>
        <form method="POST" action="#" th:action="@{/upload}" th:object="${fileContainer}"
              enctype="multipart/form-data">
            <h4>Upload files here:</h4>
            <label for="file" class="upload-drop-zone">
                Just drag and drop files <br> or click to upload.
                <input type="file" th:field="*{file}" id="file" style="display:none;"/>
            </label>
            <br><br>
            <label for="destination">Destination:</label>
            <input type="text" value="/tmp" id="destination" th:field="*{destination}"/>
            <br>
            <button class="btn btn-success convert-button btn-block" type="submit" name="upload" id="upload">Create
            </button>
            <div class="alert alert-danger" th:if="${#fields.hasErrors('file')}" th:errors="*{file}"></div>
            <div class="alert alert-danger" th:if="${#fields.hasErrors('destination')}"
                 th:errors="*{destination}"></div>
        </form>

    </div>
</div>
</div>

</body>

</html>

1 个答案:

答案 0 :(得分:1)

您不再使用“真实”FileContainerValidator

@MockBean
private FileContainerValidator fileContainerValidator;

要求Spring创建FileContainerValidator的虚假版本。 因此,FileContainerValidator中的任何实际代码都将不再被调用。

如果您使用:

@SpyBean
private FileContainerValidator fileContainerValidator;

这确实使用了真正的实现,但允许你模拟奇数方法。所以你对fileContainerValidator.supports方法的嘲讽应该仍然有用。