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

Spring Boot微服务JUnit测试:跨服务获取并使用JWT Token

Spring Boot微服务Controller测试中JWT Token获取与配置读取问题

问题描述

在Spring Boot微服务项目中编写支付、商品、订单服务的JUnit Controller测试时,遇到以下问题:
项目引入Auth服务处理用户创建和JWT登录,API网关启用JWTFilter后,所有测试请求必须携带Bearer Token。尝试自行生成Token时,无法读取application-test.yaml中的jwt.secret配置,触发报错。

报错信息

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'jwt.secret' in value "${jwt.secret}"

相关代码

测试方法示例

@Test
@DisplayName("Place Order -- Success Scenario")
void test_When_placeOrder_DoPayment_Success() throws Exception {

    OrderRequest orderRequest = getMockOrderRequest();
    String jwt = getJWTTokenForRoleUser();

    MvcResult mvcResult
            = mockMvc.perform(MockMvcRequestBuilders.post("/order/placeorder")
                    .contentType(MediaType.APPLICATION_JSON_VALUE)
                    .header("Authorization", "Bearer " + jwt)
                    .content(objectMapper.writeValueAsString(orderRequest)))
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andReturn();

    String orderId = mvcResult.getResponse().getContentAsString();

    Optional<Order> order = orderRepository.findById(Long.valueOf(orderId));
    assertTrue(order.isPresent());

    Order o = order.get();
    assertEquals(Long.parseLong(orderId), o.getId());
    assertEquals("PLACED", o.getOrderStatus());
    assertEquals(orderRequest.getTotalAmount(), o.getAmount());
    assertEquals(orderRequest.getQuantity(), o.getQuantity());
}

Token生成相关代码

private String getJWTTokenForRoleUser(){

    var loginRequest = new LoginRequest("User1","user1");

    String jwt = jwtUtils.generateJwtToken(loginRequest.getUsername());

    return jwt;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginRequest {

  private String username;
  private String password;

}

JwtUtils类实现

@Component
public class JwtUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(JwtUtils.class);

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Value("${jwt.expireMs}")
    private int jwtExpirationMs;

    public String generateJwtToken(String username) {
        return generateTokenFromUsername(username);
    }

    public String generateTokenFromUsername(String username) {
        return Jwts.builder().setSubject(username).setIssuedAt(new Date())
                .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
                .signWith(SignatureAlgorithm.HS512, jwtSecret).compact();
    }
}

项目运行步骤

  • 运行Service Registry(Eureka Server)
  • 运行Config Server
  • 通过Docker命令启动Zipkin和Redis:
docker run -d -p 9411:9411 openzipkin/zipkin 
docker run -d --name redis -p 6379:6379 redis
  • 运行API网关
  • 运行Auth服务、商品服务、订单服务和支付服务

解决方案建议

1. 确保测试环境正确加载配置文件

  • 在测试类上添加注解指定测试配置文件:
    @SpringBootTest
    @TestPropertySource(locations = "classpath:application-test.yaml")
    public class OrderControllerTest {
        // 测试代码
    }
    
  • 若依赖Config Server,可在测试配置中直接写入jwt.secret和jwt.expireMs,或关闭Config Server依赖:
    # application-test.yaml
    spring.cloud.config.enabled: false
    jwt.secret: your-test-secret-key
    jwt.expireMs: 3600000
    

2. 调用Auth服务真实接口获取Token(集成测试)

  • 注入RestTemplate,调用Auth服务的登录接口获取真实Token:
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private ObjectMapper objectMapper;
    
    private String getJWTTokenFromAuthService() throws JsonProcessingException {
        LoginRequest loginRequest = new LoginRequest("User1", "user1");
        ResponseEntity<String> response = restTemplate.postForEntity(
            "http://localhost:8080/auth/login", // Auth服务的实际地址
            loginRequest,
            String.class
        );
        JsonNode jsonNode = objectMapper.readTree(response.getBody());
        return jsonNode.get("token").asText();
    }
    
  • 此方式需保证Auth服务在测试时处于运行状态,属于集成测试场景。

3. Mock JwtUtils或跳过JWT验证(单元测试)

  • 若为单元测试,MockJwtUtils返回固定Token:
    @MockBean
    private JwtUtils jwtUtils;
    
    @BeforeEach
    void setUp() {
        when(jwtUtils.generateJwtToken(anyString())).thenReturn("mock-valid-jwt-token");
    }
    
  • 或直接关闭过滤器,跳过JWT验证:
    @AutoConfigureMockMvc(addFilters = false)
    public class OrderControllerTest {
        // 测试代码
    }
    

4. 检查配置文件位置与优先级

  • 确保application-test.yaml放置在src/test/resources目录下,测试时能被正确加载。
  • 若存在多环境配置,确认测试环境的配置优先级高于其他环境。

内容的提问来源于stack exchange,提问作者Sercan Noyan Germiyanoğlu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 16:25:24