导读:本期聚焦于小伙伴创作的《Spring Boot微服务控制器测试时如何处理跨服务调用与JWT认证》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Spring Boot微服务控制器测试时如何处理跨服务调用与JWT认证》有用,将其分享出去将是对创作者最好的鼓励。

Spring Boot微服务架构下,控制器作为对外提供接口的第一层,其测试需要覆盖接口逻辑、参数校验、权限校验等多个维度。但在实际测试中,跨服务调用和JWT认证是两个常见的阻碍点,前者会让测试依赖外部服务状态,后者要求请求必须携带合法令牌,否则无法通过权限校验。

Spring Boot微服务控制器测试时如何处理跨服务调用与JWT认证

跨服务调用的测试处理方案

微服务中控制器经常会调用其他服务的接口获取数据,比如订单服务调用用户服务查询用户信息。如果测试时发起真实的跨服务调用,一旦用户服务不可用或者返回数据不符合预期,就会导致控制器测试失败,而且真实调用还会增加测试执行时间。因此我们需要使用Mock技术模拟跨服务调用的返回结果。

使用MockBean模拟Feign客户端调用

如果项目中使用Feign作为跨服务调用的客户端,只需要在测试类中用@MockBean注解标记Feign客户端,然后定义其方法的返回结果即可。以下是示例代码:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.mockito.Mockito.when;

// 指定要测试的控制器类
@WebMvcTest(OrderController.class)
public class OrderControllerTest {
    @Autowired
    private MockMvc mockMvc;

    // 模拟Feign客户端,避免真实跨服务调用
    @MockBean
    private UserFeignClient userFeignClient;

    @Test
    public void testGetOrderWithUserInfo() throws Exception {
        // 模拟跨服务调用返回的用户信息
        UserInfo mockUserInfo = new UserInfo(1L, "测试用户", "13800138000");
        when(userFeignClient.getUserById(1L)).thenReturn(mockUserInfo);

        // 发起接口请求,验证返回状态
        mockMvc.perform(get("/orders/1"))
               .andExpect(status().isOk());
    }
}

使用WireMock模拟HTTP接口调用

如果是通过RestTemplate等工具直接发起HTTP跨服务调用,可以使用WireMock在本地启动一个模拟服务,返回预设的响应数据。首先需要引入WireMock依赖,然后配置模拟接口的响应:

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
public class ProductControllerTest {
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    private WireMockServer wireMockServer;

    @BeforeEach
    public void setup() {
        // 启动WireMock服务,端口设置为8081
        wireMockServer = new WireMockServer(8081);
        wireMockServer.start();
        WireMock.configureFor("localhost", 8081);
        // 模拟库存服务的查询接口返回
        WireMock.stubFor(WireMock.get(WireMock.urlEqualTo("/inventory/1"))
                .willReturn(WireMock.aResponse()
                        .withHeader("Content-Type", "application/json")
                        .withBody("{"productId":1,"stock":100}")));
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

    @AfterEach
    public void teardown() {
        wireMockServer.stop();
    }

    @Test
    public void testGetProductWithStock() throws Exception {
        mockMvc.perform(get("/products/1"))
               .andExpect(status().isOk());
    }
}

JWT认证的测试处理方案

微服务中通常会通过JWT令牌做接口权限校验,控制器层的拦截器或者过滤器会校验请求头中的Authorization字段,如果令牌不合法或者过期,就会直接返回401错误。因此测试时需要构造合法的JWT令牌添加到请求头中。

生成测试用JWT令牌

我们可以编写一个工具类生成测试专用的JWT令牌,令牌的签名密钥和过期时间可以和正式环境保持一致,但是可以简化载荷内容,只保留必要的用户标识和权限信息:

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtTestUtil {
    // 和项目配置一致的JWT签名密钥
    private static final String SECRET_KEY = "test-secret-key-123456";
    // 令牌过期时间,测试场景可以设置较长
    private static final long EXPIRATION_TIME = 3600000;

    public static String generateTestToken(Long userId, String role) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", userId);
        claims.put("role", role);
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }
}

在测试请求中添加JWT令牌

生成令牌之后,只需要在MockMvc发起请求时,通过header方法添加Authorization请求头即可,格式为Bearer 空格加令牌内容:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.mockito.Mockito.when;

@WebMvcTest(UserController.class)
public class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    public void testGetUserInfoWithJwt() throws Exception {
        // 生成测试用JWT令牌,用户ID为1,角色为普通用户
        String token = JwtTestUtil.generateTestToken(1L, "ROLE_USER");
        when(userService.getUserById(1L)).thenReturn(new UserInfo(1L, "测试用户"));

        // 添加Authorization请求头,携带JWT令牌
        mockMvc.perform(get("/users/1")
                .header("Authorization", "Bearer " + token))
               .andExpect(status().isOk());
    }

    @Test
    public void testGetUserInfoWithoutJwt() throws Exception {
        // 不携带令牌,预期返回401未授权
        mockMvc.perform(get("/users/1"))
               .andExpect(status().isUnauthorized());
    }
}

综合测试场景示例

实际测试中经常会同时遇到跨服务调用和JWT认证的场景,我们可以把两种处理方式结合起来,既模拟跨服务调用的返回,又添加合法的JWT令牌到请求中:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.mockito.Mockito.when;

@WebMvcTest(OrderController.class)
public class OrderControllerIntegratedTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserFeignClient userFeignClient;

    @MockBean
    private ProductFeignClient productFeignClient;

    @Test
    public void testCreateOrder() throws Exception {
        // 生成管理员角色的JWT令牌
        String token = JwtTestUtil.generateTestToken(1L, "ROLE_ADMIN");
        // 模拟用户服务返回
        when(userFeignClient.getUserById(1L)).thenReturn(new UserInfo(1L, "管理员"));
        // 模拟商品服务返回
        when(productFeignClient.getProductById(1L)).thenReturn(new ProductInfo(1L, "测试商品", 100));

        // 发起创建订单请求,携带令牌和模拟的跨服务调用
        mockMvc.perform(post("/orders")
                .header("Authorization", "Bearer " + token)
                .param("userId", "1")
                .param("productId", "1")
                .param("count", "2"))
               .andExpect(status().isOk());
    }
}

注意事项

  • Mock的跨服务调用返回数据需要和真实接口的返回结构保持一致,否则控制器处理时可能会出现反序列化错误。
  • 测试用的JWT令牌密钥需要和项目正式配置的密钥一致,否则会被校验为非法令牌。
  • 如果项目中使用了自定义的JWT校验逻辑,需要确认测试环境是否加载了对应的校验配置,避免出现校验逻辑不生效的情况。
  • 测试完成后不需要清理JWT令牌,因为令牌是客户端生成的,不会在服务端存储状态。

Spring_Boot微服务控制器测试JWT认证跨服务调用修改时间:2026-07-17 21:48:54

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。