我正在尝试编写集成测试,目的是验证文件上传。
正常文件上传按预期工作(文件在满足要求时上传),但测试不执行并引发错误。
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")
);
}
}
答案 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")
);
}