在我之前的一篇文章中,我创建了一个 API 来上传文件。在这篇文章中,我将编写一个 JUnit 测试来测试 API。我们将测试从上传到复制到文件系统的完整流程,然后我们还将看到如何模拟 FileService 类,以便上传的文件不会复制到文件系统。
@Slf4j
@RestController
@RequestMapping("/api/files")
public class FileUploadAPIController {
@Autowired FileService fileService;
@PostMapping("/upload")
public ResponseEntity> handleFileUpload(
@RequestParam("uploaded-file") List uploadedFiles
) throws IOException {
log.debug("Uploaded files size : {}", uploadedFiles.size());
fileService.copyFile(uploadedFiles);
return ResponseEntity.ok().build();
}
}
- 第 1-4 行:使用基本 URL 声明 RESTful API:/api/files
- 第 6 行:注入FileService用于将上传的文件复制到文件系统的托管 bean
- 第 8 行:将通过 HTTP POST 可用的上传 API 映射到 URL:/api/files/upload
- 第 10 行:接受超过 1 个使用请求参数名称上传的文件uploaded-file
- 第 12-14 行:API 的实现
以下代码用于测试文件上传 API。在此,我们将测试将文件发送到 API 然后将 copid 发送到文件系统的完整流程:
@SpringBootTest
@AutoConfigureMockMvc
public class FileUploadAPIControllerE2ETest {
@Autowired
MockMvc mockMvc;
@Value("${app.document-root}")String documentRoot;
List filesToBeDeleted = new ArrayList<>();
@Test
public void test_handleFileUpload() throws Exception {
String fileName = "sampleFile.txt";
MockMultipartFile sampleFile = new MockMultipartFile(
"uploaded-file",
fileName,
"text/plain",
"This is the file content".getBytes()
);
MockMultipartHttpServletRequestBuilder multipartRequest =
MockMvcRequestBuilders.multipart("/api/files/upload");
mockMvc.perform(multipartRequest.file(sampleFile))
.andExpect(status().isOk());
Path docRootPath = Path.of(documentRoot, fileName);
filesToBeDeleted.add(docRootPath);
assertThat(Files.exists(docRootPath)).isTrue();
}
@AfterEach
public void cleanup() {
filesToBeDeleted.forEach(path -> {
try {
Files.deleteIfExists(path);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
- 第 1-2 行:@SpringBootTestannoation 创建一个模拟 Web 服务器并@AutoConfigureMockMvc配置一个@MockMvc对象,该对象可用于调用代码中定义的 API
- 第 7 行:注入复制文件的根目录路径。当我们调用 API 进行测试时,我们将使用它来验证文件是否实际被复制。
- 第9、33-42行:记录上传文件在文件系统中的位置,以便我们在每次测试结束时进行清理。这样我们的测试将是可重复的。
- 第 13-19 行:创建要上传的文件。Spring 提供了一个MultipartFile调用的实现,MockMultipartFile可用于向 API 提供文件。
- 第 21-25 行:通过提供之前创建的文件并断言响应为 HTTP 状态 200 来调用 API。
- 第 27-29 行:断言文件已复制到所需的目标。
在此测试中,我们将使用 模拟FileServicebean,@MockBean该 bean 负责将上传的文件复制到文件系统中的所需位置。在这个测试中,我们将只测试 API 代码,而不关注它所依赖的下游服务。
@SpringBootTest
@AutoConfigureMockMvc
public class FileUploadAPIControllerTest {
@MockBean private FileService fileService;
@Autowired MockMvc mockMvc;
@Value("${app.document-root}")String documentRoot;
@Test
public void test_handleFileUpload() throws Exception{
String fileName = "sample-file-mock.txt";
MockMultipartFile sampleFile = new MockMultipartFile(
"uploaded-file",
fileName,
"text/plain",
"This is the file content".getBytes());
MockMultipartHttpServletRequestBuilder multipartRequest =
MockMvcRequestBuilders.multipart("/api/files/upload");
mockMvc.perform(multipartRequest.file(sampleFile))
.andExpect(status().isOk());
}
@Test
public void test_handleFileUpload_NoFileProvided() throws Exception{
MockMultipartHttpServletRequestBuilder multipartRequest =
MockMvcRequestBuilders.multipart("/api/files/upload");
mockMvc.perform(multipartRequest)
.andExpect(status().isBadRequest());
}
}
- FileService第 4 行:通过 annotation 使用 Mockito 模拟spring 托管 bean @MockBean。这个注解对于模拟 spring 管理的 bean 很有用
其余代码类似于前面显示的端到端测试。在这个测试中,我们不验证文件系统上文件的存在,因为复制到文件系统的实现已被模拟,并且模拟的托管 bean 中没有真正的实现。
完整的代码——API、视图和测试可以在这里的 Github repo 中找到。
学习更多JAVA知识与技巧,关注与私信博主(学习)



