Spring Boot Cucumber 测试无法解析占位符 'random.uuid'

Spring Boot Cucumber tests could not resolve placeholder 'random.uuid'

我希望 Spring Boot 属性 默认情况下无法猜测随机值(出于安全原因),所以我尝试使用 random UUID 作为默认值值,使用如下代码:

@Service
public class UserServiceImpl implements UserService {
...
   @Autowired
   public UserServiceImpl(@NonNull final PasswordEncoder passwordEncoder,
            @NonNull final UserRepository userRepository,
            @NonNull @Value("${administrator.password:${random.uuid}}") final String administratorPassword) {
      ...
   }

但是我的 Cucumber Spring 引导测试抱怨 ${random.uuid} 因此:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userServiceImpl' defined in file [.../UserServiceImpl.class]: Unexpected exception during bean creation; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'random.uuid' in value "administrator.password:${random.uuid}"

我需要做什么才能让我的应用程序使用随机 属性 值?

${random.uuid} 只能在 RandomValuePropertySource 可用时使用。

作为解决方法,您可以定义一个“虚拟默认值”并在您的代码中检测到它:

   @Autowired
   public UserServiceImpl(@NonNull final PasswordEncoder passwordEncoder,
            @NonNull final UserRepository userRepository,
            @NonNull @Value("${administrator.password:no-default-vale-provided}") final String administratorPassword) {
      this.adminPassword = "no-default-value-provided".equals(administratorPassword)
              ? UUID.randomUUID().toString()
              : administratorPassword;
   }

如果您有 [`RandomValuePropertySource`](https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/env/RandomValuePropertySource.html) 可用,那么 SpEL 表达式 `${random.uuid}` 应该确实解析到一个随机的 UUID。 `${...}` 是 属性 占位符,`#{$...}` 是 SpEL 语法。

您需要更改注释:

@NonNull @Value("#{${administrator.password} ?: ${random.uuid}}") final String administratorPassword

问题可能与测试切片有关。如果我 运行 一个干净的 Spring 启动项目测试:

@SpringBootTest
class DemoApplicationTests {

    @Value("${nonexistingValue:${random.uuid}}")
    private String someVal;

    @Test
    public void someTest() {
        assertThat(someVal).contains("-");
    }

}

测试通过。但是,如果我将 @SpringBootTest 更改为 @ExtendWith({SpringExtension.class})@RunWith(SpringRunner.class),测试将失败。 ${random.uuid} 和类似的表达式应该在正常的 运行 时间环境中可用。


因为这个切片,似乎 RandomValuePropertySource 不可用。一个相当不优雅的解决方法是使用在测试上下文中创建的 PropertySourcesPlaceholderConfigurer bean 将它显式添加到上下文中:

@Configuration
public class CucumberBeansConfiguration {

   @Bean
   public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
      final var configurer = new PropertySourcesPlaceholderConfigurer();
      final var sources = new MutablePropertySources();
      sources.addFirst(new RandomValuePropertySource());
      configurer.setPropertySources(sources);
      return configurer;
   }

}

Cucumber 使用弹簧 TestContextManager。通过使用 @CucumberContextConfiguration 注释您的上下文配置,Cucumber 知道 class 使用哪个来启动测试上下文。

import com.example.app;

import org.springframework.boot.test.context.SpringBootTest;

import io.cucumber.spring.CucumberContextConfiguration;

@CucumberContextConfiguration
@SpringBootTest
public class CucumberSpringConfiguration {

}

确保 CucumberSpringConfigurationcucumber.glue 路径上。