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

如何使用JUnit和Mockito模拟Feign拦截器中的OAuth2AuthorizedClientManager?

JUnit + Mockito 测试Feign OAuth2拦截器

前置依赖

确保测试包中包含以下依赖:

  • JUnit 5 (Jupiter)
  • Mockito Core 及 Mockito JUnit Jupiter 扩展
  • Spring Cloud Feign 基础依赖
  • Spring Security OAuth2 相关测试依赖

测试实现

假设你的拦截器定义在FeignConfig类中,以下是完整的测试类:

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.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.http.HttpHeaders;

import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

@ExtendWith(MockitoExtension.class)
public class FeignOAuth2InterceptorTest {

    @Mock
    private OAuth2AuthorizedClientManager authorizedClientManager;

    @InjectMocks
    private FeignConfig feignConfig;

    @Test
    void interceptorAddsValidBearerTokenToRequest() {
        // 1. 准备测试数据
        String mockToken = "sample-access-token-xyz";
        Authentication mockAuth = mock(Authentication.class);
        OAuth2AccessToken accessToken = mock(OAuth2AccessToken.class);
        OAuth2AuthorizedClient authorizedClient = mock(OAuth2AuthorizedClient.class);

        // 设置Security上下文
        SecurityContextHolder.getContext().setAuthentication(mockAuth);

        // 2. 配置Mock行为
        when(accessToken.getTokenValue()).thenReturn(mockToken);
        when(authorizedClient.getAccessToken()).thenReturn(accessToken);
        when(authorizedClientManager.authorize(any(OAuth2AuthorizeRequest.class)))
                .thenReturn(authorizedClient);

        // 3. 执行拦截逻辑
        RequestInterceptor interceptor = feignConfig.requestInterceptor();
        RequestTemplate requestTemplate = new RequestTemplate();
        interceptor.apply(requestTemplate);

        // 4. 验证结果
        String authHeader = requestTemplate.headers().get(HttpHeaders.AUTHORIZATION).get(0);
        assertEquals("Bearer " + mockToken, authHeader);

        // 验证授权请求参数是否正确
        verify(authorizedClientManager, times(1))
                .authorize(argThat(req -> 
                        "keycloak".equals(req.getClientRegistrationId())
                        && mockAuth.equals(req.getPrincipal())
                ));

        // 清理Security上下文
        SecurityContextHolder.clearContext();
    }

    @Test
    void interceptorThrowsExceptionWhenAuthorizedClientIsNull() {
        Authentication mockAuth = mock(Authentication.class);
        SecurityContextHolder.getContext().setAuthentication(mockAuth);

        // 模拟授权失败返回null
        when(authorizedClientManager.authorize(any(OAuth2AuthorizeRequest.class)))
                .thenReturn(null);

        RequestInterceptor interceptor = feignConfig.requestInterceptor();
        RequestTemplate requestTemplate = new RequestTemplate();

        // 验证空指针异常抛出
        assertThrows(NullPointerException.class, () -> interceptor.apply(requestTemplate));

        SecurityContextHolder.clearContext();
    }
}

核心测试逻辑说明

  • Security上下文模拟:拦截器依赖SecurityContextHolder获取认证信息,测试时需手动设置模拟的Authentication,测试完成后必须清理上下文,避免影响其他用例。
  • Mock依赖行为:通过Mockito模拟OAuth2AuthorizedClientManager的返回值,构造完整的授权令牌链路,确保拦截器能正确获取令牌。
  • 参数校验:使用argThat验证authorize方法接收的OAuth2AuthorizeRequest是否符合预期(客户端ID为"keycloak"、principal为当前认证对象)。
  • 异常场景覆盖:测试授权失败返回null的情况,验证拦截器的异常处理逻辑(当前实现会抛出NPE,若实际业务有容错处理,需对应调整测试)。

注意事项

  • 确保FeignConfig中的requestInterceptor()方法为public,否则测试类无法调用。
  • 若FeignConfig存在其他依赖,需通过@Mock模拟并配合@InjectMocks完成注入。
  • 测试时尽量覆盖正常流程、异常流程等核心场景,保证拦截器逻辑的健壮性。

内容的提问来源于stack exchange,提问作者springLover

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 21:12:47