基于Spring框架与Mockito的JUnit文件校验测试实现咨询
没问题!结合Spring和Mockito来模拟文件操作完全可行,不用碰真实文件系统就能完成所有校验逻辑。我给你梳理一套完整的实现方案,包含你提到的所有校验点:
整体思路
核心是通过Mockito模拟Spring的ResourceLoader或具体的Resource对象,避免依赖真实文件;同时用Spring Test提供的MockHttpServletRequest来模拟上下文头信息。这样我们可以精准控制每个校验场景的输入,覆盖所有分支。
目标服务类示例
先假设你有一个负责文件校验的服务类,包含你需要的所有校验逻辑:
import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Service; import org.springframework.util.StreamUtils; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.nio.charset.StandardCharsets; @Service public class FileValidationService { private final ResourceLoader resourceLoader; public FileValidationService(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } public ValidationResult validateFile(HttpServletRequest request, String filePath) throws IOException { // 1. 从上下文头获取用户令牌 String userToken = request.getHeader("X-User-Token"); if (userToken == null || userToken.isBlank()) { return ValidationResult.fail("用户令牌缺失"); } // 2. 检查文件是否存在 Resource resource = resourceLoader.getResource(filePath); if (!resource.exists()) { return ValidationResult.fail("文件不存在"); } // 3. 校验文件长度(限制1MB) long fileSize = resource.contentLength(); if (fileSize > 1024 * 1024) { return ValidationResult.fail("文件超过1MB大小限制"); } // 4. 校验文件内容包含指定标记 String content = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8); if (!content.contains("VALID_CONTENT_MARKER")) { return ValidationResult.fail("文件内容不符合要求"); } return ValidationResult.success("所有校验通过"); } // 内部结果封装类 public static class ValidationResult { private final boolean success; private final String message; private ValidationResult(boolean success, String message) { this.success = success; this.message = message; } public static ValidationResult success(String message) { return new ValidationResult(true, message); } public static ValidationResult fail(String message) { return new ValidationResult(false, message); } // Getter方法 public boolean isSuccess() { return success; } public String getMessage() { return message; } } }
JUnit测试用例实现
使用JUnit 5 + Mockito + Spring Test来编写测试,覆盖所有校验场景:
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.mock.web.MockHttpServletRequest; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class FileValidationServiceTest { @Mock private ResourceLoader resourceLoader; @InjectMocks private FileValidationService validationService; private MockHttpServletRequest mockRequest; @BeforeEach void setUp() { // 初始化模拟请求对象 mockRequest = new MockHttpServletRequest(); } @Test void validateFile_shouldReturnSuccess_whenAllChecksPass() throws IOException { // 1. 模拟上下文头存在有效令牌 mockRequest.addHeader("X-User-Token", "valid-token-123"); // 2. 模拟存在的文件资源 String mockFilePath = "classpath:test-file.txt"; Resource mockResource = mock(Resource.class); when(resourceLoader.getResource(mockFilePath)).thenReturn(mockResource); when(mockResource.exists()).thenReturn(true); // 3. 模拟文件大小符合限制 when(mockResource.contentLength()).thenReturn(512L); // 4. 模拟文件内容包含有效标记 String validContent = "Sample content with VALID_CONTENT_MARKER"; InputStream mockInputStream = new ByteArrayInputStream(validContent.getBytes(StandardCharsets.UTF_8)); when(mockResource.getInputStream()).thenReturn(mockInputStream); // 执行校验 FileValidationService.ValidationResult result = validationService.validateFile(mockRequest, mockFilePath); // 断言结果 assertTrue(result.isSuccess()); assertEquals("所有校验通过", result.getMessage()); } @Test void validateFile_shouldReturnFail_whenHeaderMissing() throws IOException { // 不设置任何上下文头 String mockFilePath = "classpath:test-file.txt"; // 执行校验 FileValidationService.ValidationResult result = validationService.validateFile(mockRequest, mockFilePath); // 断言结果 assertFalse(result.isSuccess()); assertEquals("用户令牌缺失", result.getMessage()); } @Test void validateFile_shouldReturnFail_whenFileDoesNotExist() throws IOException { // 模拟上下文头有效 mockRequest.addHeader("X-User-Token", "valid-token-123"); // 模拟文件不存在 String mockFilePath = "classpath:non-existent-file.txt"; Resource mockResource = mock(Resource.class); when(resourceLoader.getResource(mockFilePath)).thenReturn(mockResource); when(mockResource.exists()).thenReturn(false); // 执行校验 FileValidationService.ValidationResult result = validationService.validateFile(mockRequest, mockFilePath); // 断言结果 assertFalse(result.isSuccess()); assertEquals("文件不存在", result.getMessage()); } @Test void validateFile_shouldReturnFail_whenFileSizeExceedsLimit() throws IOException { // 模拟上下文头有效 mockRequest.addHeader("X-User-Token", "valid-token-123"); // 模拟文件存在但大小超过1MB String mockFilePath = "classpath:large-file.txt"; Resource mockResource = mock(Resource.class); when(resourceLoader.getResource(mockFilePath)).thenReturn(mockResource); when(mockResource.exists()).thenReturn(true); when(mockResource.contentLength()).thenReturn(2 * 1024 * 1024L); // 2MB // 执行校验 FileValidationService.ValidationResult result = validationService.validateFile(mockRequest, mockFilePath); // 断言结果 assertFalse(result.isSuccess()); assertEquals("文件超过1MB大小限制", result.getMessage()); } @Test void validateFile_shouldReturnFail_whenContentInvalid() throws IOException { // 模拟上下文头有效 mockRequest.addHeader("X-User-Token", "valid-token-123"); // 模拟文件存在但内容无有效标记 String mockFilePath = "classpath:invalid-content.txt"; Resource mockResource = mock(Resource.class); when(resourceLoader.getResource(mockFilePath)).thenReturn(mockResource); when(mockResource.exists()).thenReturn(true); when(mockResource.contentLength()).thenReturn(256L); String invalidContent = "Sample content without valid marker"; InputStream mockInputStream = new ByteArrayInputStream(invalidContent.getBytes(StandardCharsets.UTF_8)); when(mockResource.getInputStream()).thenReturn(mockInputStream); // 执行校验 FileValidationService.ValidationResult result = validationService.validateFile(mockRequest, mockFilePath); // 断言结果 assertFalse(result.isSuccess()); assertEquals("文件内容不符合要求", result.getMessage()); } }
额外注意事项
- 如果是Spring Boot集成测试场景,可以用
@SpringBootTest结合@MockBean(ResourceLoader.class)来替换容器中的真实ResourceLoader,实现更贴近生产环境的测试 - 模拟输入流时,建议使用
ByteArrayInputStream,它不需要关闭(或JUnit会自动处理资源释放),避免测试中出现资源泄漏 - 如果你直接使用
FileSystemResource而不是ResourceLoader,同样可以用Mockito模拟FileSystemResource的exists()、contentLength()、getInputStream()等方法
内容的提问来源于stack exchange,提问作者user3468921
相关产品推荐
相关产品推荐

