Actually, this is a kind of "follow-up" question. I have 2 integration tests running for a file upload, testing the corresponding controller. Unfortunately, after using the solution of the answer from my other question, the second integration test that should "fail" (because the extension of the file is "wrong" and therefore the FileContainerValidator should reject the file) does not fail! The Validator doesn't even get called.
How to solve the problem?
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");
}
}
}
Form ("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">© 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>
You are no longer using your "real" FileContainerValidator
.
@MockBean
private FileContainerValidator fileContainerValidator;
That asks Spring to create a fake version of your FileContainerValidator
.
So any real code inside FileContainerValidator
will no longer be called.
If you use:
@SpyBean
private FileContainerValidator fileContainerValidator;
That does use the real implementation, but allows you to mock out the odd method. So your mocking of the fileContainerValidator.supports
method should still work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With