java - Spring - validator 不会在集成测试中触发

标签 java spring validation spring-mvc integration-testing

问题

其实这是一种"follow-up" question .我为文件上传运行了 2 个集成测试,测试相应的 Controller 。不幸的是,在使用我的另一个问题的答案的解决方案之后,应该“失败”的第二个集成测试(因为文件的扩展名是“错误的”,因此 FileContainerValidator 应该拒绝该文件)并没有失败! validator 甚至不会被调用。

如何解决问题?


我的代码

文件上传 Controller

@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);
    }
}

文件上传集成测试

@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"));
    }
}

文件容器 validator

@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");
        }
    }
}

表单(“upload.html”)

<!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>

最佳答案

您不再使用“真正的”FileContainerValidator

@MockBean
private FileContainerValidator fileContainerValidator;

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

如果您使用:

@SpyBean
private FileContainerValidator fileContainerValidator;

它确实使用了真正的实现,但允许您模拟奇怪的方法。所以你对 fileContainerValidator.supports 方法的模拟应该仍然有效。

关于java - Spring - validator 不会在集成测试中触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41016228/

相关文章:

java - Java + Hibernate中对象的匹配算法

validation - 您如何手动计算 Cluster 的轮廓、内聚和分离

java - MongoDB:查找所有字段和值(_id 除外)都等于给定文档的文档?

spring - jar 如何在使用它的 Web 应用程序中传播漏洞?

java - 在 Java 中使用正则表达式有选择地查找模式

spring - 如何在 Controller 中以编程方式实现 Spring Security SpEL isFullyAuthenticated() ?

javascript - 只允许 contenteditable 元素中的数字?

html5 minlength 在 chrome 版本 52.0.2743.116(64 位)中不起作用

java - WINE可以在Linux下打开独立的Windows应用程序吗?

java - Spring Boot - 如何手动创建 bean 并将其传递给 HashMap