温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何测试拦截器

发布时间:2026-08-30 06:28:46 来源:亿速云 阅读:90 作者:小樊 栏目:编程语言

测试拦截器(通常是指如 Spring MVC 的 HandlerInterceptor、MyBatis 的 Interceptor、OKHttp/Retrofit 的 Interceptor 等)需要根据具体技术栈来设计测试方案。不过,核心思路是一致的:验证在特定条件下,拦截器的逻辑是否被正确执行

下面我将以使用最广泛的 Spring MVC 的 HandlerInterceptor 为例,详细讲解如何测试,并补充其他常见场景的测试思路。


一、 测试 Spring MVC HandlerInterceptor

假设我们有一个简单的拦截器,用于检查请求头中是否存在 API-Key

示例代码:

@Component
public class ApiKeyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String apiKey = request.getHeader("API-Key");
        if (apiKey == null || apiKey.isEmpty()) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.getWriter().write("Missing API Key");
            return false; // 中断请求
        }
        return true; // 放行
    }
}

方法 1:使用 MockMvc(推荐,侧重测试行为)

这是最合适的方法,因为它模拟了 Spring MVC 的完整流程,但又不需要启动真正的服务器(速度快)。

测试代码:

@WebMvcTest(YourController.class) // 或者 @SpringBootTest
class ApiKeyInterceptorTest {

    @Autowired
    private MockMvc mockMvc;

    // 如果拦截器不是自动装配的,需要手动添加
    // @Autowired
    // private ApiKeyInterceptor apiKeyInterceptor;

    // 或者这样配置
    // @BeforeEach
    // void setup(WebApplicationContext wac) {
    //     this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).addInterceptors(apiKeyInterceptor).build();
    // }

    @Test
    @DisplayName("当缺少 API-Key 时应返回 401")
    void shouldReturnUnauthorizedWhenApiKeyMissing() throws Exception {
        mockMvc.perform(get("/some-endpoint") // 发送请求
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isUnauthorized());
    }

    @Test
    @DisplayName("当 API-Key 存在时应返回 200")
    void shouldReturnOkWhenApiKeyPresent() throws Exception {
        mockMvc.perform(get("/some-endpoint")
                .header("API-Key", "valid-key-123"))
                .andExpect(status().isOk());
    }
}

注意: 如果拦截器是通过 WebMvcConfigurer 配置的,且你在测试类上使用了 @WebMvcTest,Spring 应该会自动检测到它。如果没有,你可能需要在测试配置中手动注册拦截器。

方法 2:使用 Spring Boot Test + TestRestTemplate (集成测试)

如果你想测试真实的 HTTP 请求流程(包括 Tomcat 启动),可以使用这种方式。

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ApiKeyInterceptorIntegrationTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void testInterceptorViaRealRequest() {
        // 不带 Header
        ResponseEntity<String> response1 = restTemplate.getForEntity("/some-endpoint", String.class);
        assert response1.getStatusCode().value() == 401;

        // 带 Header
        HttpHeaders headers = new HttpHeaders();
        headers.set("API-Key", "test");
        HttpEntity<String> entity = new HttpEntity<>(headers);
        
        ResponseEntity<String> response2 = restTemplate.exchange("/some-endpoint", HttpMethod.GET, entity, String.class);
        assert response2.getStatusCode().is2xxSuccessful();
    }
}

方法 3:纯单元测试(不依赖 Spring 容器)

如果你只想测试拦截器本身的逻辑,不关心 Spring 的调度,可以直接 Mock HttpServletRequestHttpServletResponse

@ExtendWith(MockitoExtension.class)
class ApiKeyInterceptorUnitTest {

    private ApiKeyInterceptor interceptor;
    private HttpServletRequest request;
    private HttpServletResponse response;

    @BeforeEach
    void setUp() {
        interceptor = new ApiKeyInterceptor();
        request = mock(HttpServletRequest.class);
        response = mock(HttpServletResponse.class);
    }

    @Test
    void preHandle_shouldReturnFalse_whenApiKeyIsMissing() throws Exception {
        // Given
        when(request.getHeader("API-Key")).thenReturn(null);
        StringWriter stringWriter = new StringWriter();
        PrintWriter writer = new PrintWriter(stringWriter);
        when(response.getWriter()).thenReturn(writer);

        // When
        boolean result = interceptor.preHandle(request, response, new Object());

        // Then
        assertFalse(result);
        verify(response).setStatus(HttpStatus.UNAUTHORIZED.value());
    }

    @Test
    void preHandle_shouldReturnTrue_whenApiKeyIsPresent() throws Exception {
        // Given
        when(request.getHeader("API-Key")).thenReturn("abc");

        // When
        boolean result = interceptor.preHandle(request, response, new Object());

        // Then
        assertTrue(result);
    }
}

二、 测试 MyBatis 拦截器 (Interceptor)

MyBatis 的拦截器主要用于 SQL 重写、分页等。测试起来稍微复杂,通常需要:

  1. 构建 Configuration:手动创建 MyBatis 的 Configuration 对象。
  2. 注册拦截器:将拦截器实例添加到 Configuration 中。
  3. 模拟执行:通过 SqlSessionFactory 构建会话并执行方法,验证 SQL 是否被修改。

示例思路:

@Test
void testMyBatisInterceptor() {
    // 1. 创建配置
    Configuration configuration = new Configuration();
    Environment environment = new Environment("test", new JdbcTransactionFactory(), mock(DataSource.class));
    configuration.setEnvironment(environment);
    
    // 2. 添加拦截器
    MyCustomInterceptor interceptor = new MyCustomInterceptor();
    configuration.addInterceptor(interceptor);

    // 3. 添加 Mapper 并执行
    configuration.addMapper(UserMapper.class);
    
    try (SqlSession session = new SqlSessionFactoryBuilder().build(configuration).openSession()) {
        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.selectById(1); // 这里会触发拦截器
        // 验证拦截器内部的逻辑是否执行(例如通过 spy 或静态标记)
    }
}

三、 测试 OKHttp / Retrofit 拦截器

对于网络库中的拦截器,测试通常是通过MockWebServer配合测试。

示例思路:

@Test
void testOkHttpInterceptor() throws IOException {
    MockWebServer server = new MockWebServer();
    server.start();
    server.enqueue(new MockResponse().setBody("{\"status\":\"ok\"}"));

    // 1. 添加拦截器到 OkHttpClient
    OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(new LoggingInterceptor()) // 你的拦截器
            .build();

    // 2. 发起请求
    Request request = new Request.Builder()
            .url(server.url("/test"))
            .build();
    
    Response response = client.newCall(request).execute();

    // 3. 验证
    assertEquals(200, response.code());
    
    // 验证拦截器是否添加了 Header 等
    RecordedRequest recordedRequest = server.takeRequest();
    assertEquals("expected_header_value", recordedRequest.getHeader("Custom-Header"));

    server.shutdown();
}

总结:测试拦截器的关键步骤

  1. 明确拦截点:确定是 preHandle(请求前)、postHandle(视图渲染前)还是 afterCompletion(完成后)。
  2. 准备上下文
    • Spring: 使用 MockHttpServletRequestMockMvc
    • MyBatis: 需要构建 Configuration
    • OKHttp: 使用 MockWebServer
  3. 模拟依赖:Mock 掉 HttpServletRequestDataSourceChain 对象。
  4. 验证逻辑
    • 验证返回值(通常是 truefalse)。
    • 验证 Mock 对象的交互(例如 response.setStatus(401) 是否被调用)。
    • 验证副作用(例如数据库记录被修改、日志被打印、Header 被添加)。

建议: 对于 Spring 项目,优先使用 MockMvc 测试拦截器,因为它最接近真实使用情况且速度较快。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI