如何在 Spring 启动测试中使用环境变量?

How can I use env variables with Spring Boot Test?

在我的 Spring Boot Security 应用程序中,我将我的秘密存储在文件 application.properties 中并且它可以正常工作 fine.I 可以像这样获取我的秘密密钥:

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

但是为了测试它并且不要在我的测试中硬编码秘密密码,我需要生成我的令牌并将其放在我的授权中header(使用 mockMvc),但我无法从测试 class 访问我的秘密环境变量,即使我在测试路径的 application.properties 文件中插入我的环境变量。

我如何为我的测试生成令牌:

public class TokenForTest {
    public static String generateTokenForTest() {
        Date today = new Date();
        Date expireDate = new Date(today.getTime() + Long.parseLong("86400000"));
        return "Bearer " + Jwts.builder()
                .setIssuer("BeatSound API")
                .setSubject("1")
                .setIssuedAt(today)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS256, "secretKey")
                .compact();
    }
}

我是如何进行测试的:

 @Test
        void shouldReturnAllUsers() throws Exception {
                String token = TokenForTest.generateTokenForTest();
                this.mockMvc.perform(get("/api/v1/user")
                        .header("Authorization", token))
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
                        .andExpect(status().isOk()).andDo(print())
                        .andExpect(jsonPath("$.[*].id").exists())
                        .andExpect(jsonPath("$.[*].name").exists())
                        .andExpect(jsonPath("$.[*].email").exists())
                        .andExpect(jsonPath("$.[*].password").exists())
        }

在测试期间,最好只使用 src/test/resources/application-test.properties:

中的值
secret=test secret

请注意文件名,有这个“测试”后缀。这是因为 Spring 默认情况下在“测试”配置文件中启动 运行s 测试。 此属性文件是定义测试配置的地方。 选择将在测试中使用的良好示例值。 不要从环境中为测试注入示例值,因为这样做会使您的测试在一个环境中失败并在另一个环境中通过。

要为正常 运行 配置应用程序属性,请使用文件 src/main/resources/application.properties:

secret=${SECRET}

这样您就可以使用 ${ENVIRONMENT_VARIABLE_NAME} 语法将环境变量注入应用程序属性。 不像在测试 运行 期间你想要坚持具体的示例值,在你的应用程序的正常 运行 期间,最好让你的应用程序属性从 environment variables 注入。 现在,如果您像这样启动您的应用程序:

export SECRET=secretFromEnv
mvn spring-boot:run

它将以值为“secretFromEnv”的应用程序属性“secret”开始。就像您拥有它一样 secret=secretFromEnv,但它可以在其他环境中设置不同(例如:暂存、生产)。

要在 spring 引导代码中使用应用程序 属性 值,如问题中所述,可以使用 @Value 注释:

@Service
public class MyService {
  @Value("${secret}")
  private String secret;

  public String getSecret() { 
    return secret;
  }
}

而这个服务的测试可以是这样的:

class MyServiceTest extends IntegrationTestRunner {

  @Autowired MyService service;

  @Test
  public void testSecret() {
    var serviceSecret = service.getSecret();
    assertEquals("test secret", serviceSecret);
  }
}

此测试断言应用程序配置中的示例值由服务返回。在实际运行期间,该值将从环境变量中注入,假设我们的环境变量设置为:

export SECRET=secret-from-env

然后 spring 引导应用程序在 shell:

中启动

mvn spring-boot:运行

所以现在说如果在你的休息控制器中有这样的代码:

@Autowired MyService service;

@GetMapping(path = "/secret")
@ResponseBody public String getSecret() {
  return service.getSecret();
}

然后调用 HTTP GET /secret 将打印“secret-from-env”,因为这是环境变量 $SECRET 的值。

这样做:

  • 允许我们拥有用于测试的示例应用程序属性;
  • 对于非测试设置,值是从环境变量中注入的;