You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:48:48