1. 개요
우리의 이전 사용방법(예제)에서는 @ConfigurationProperties , 우리는 설정하고 사용하는 방법을 배웠습니다 @ConfigurationProperties의 외부 구성 작업을위한 Spring 부팅과 어노테이션을.
이 예제에서는 구성 데이터가 해당 필드에 올바르게로드되고 바인딩되는지 확인하기 위해 @ConfigurationProperties 어노테이션 에 의존하는 구성 클래스를 테스트하는 방법을 보여줍니다 .
2. 의존성
Maven 프로젝트에서는 spring-boot-starter 및 spring-boot-starter-test 의존성을 사용하여 각각 핵심 스프링 API와 Spring의 테스트 API를 활성화합니다.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
또한 나중에 사용할 것이므로 빈 유효성 검사 의존성으로 프로젝트를 구성 해 보겠습니다 .
<!-- JSR-380 bean validation -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.6</version>
</dependency>
3. 사용자 정의 POJO에 대한 속성 바인딩
외부화 된 구성으로 작업 할 때 일반적으로 일치하는 구성 속성에 해당하는 필드를 포함하는 POJO를 만듭니다 . 이미 알고 있듯이 Spring은 자동으로 구성 속성을 우리가 만든 Java 클래스에 바인딩합니다.
우선, src / test / resources / server-config-test.properties 라고 부르는 속성 파일 내에 서버 구성이 있다고 가정 해 보겠습니다 .
server.address.ip=192.168.0.1
server.resources_path.imgs=/root/imgs
이제 이전 속성 파일에 해당하는 간단한 구성 클래스를 정의 해 보겠습니다.
@Configuration
@ConfigurationProperties(prefix = "server")
public class ServerConfig {
private Address address;
private Map<String, String> resourcesPath;
// getters and setters
}
또한 해당 주소 유형 :
public class Address {
private String ip;
// getters and setters
}
마지막으로 ServerConfig POJO를 테스트 클래스에 삽입하고 모든 필드가 올바르게 설정되었는지 확인합니다.
@ExtendWith(SpringExtension.class)
@EnableConfigurationProperties(value = ServerConfig.class)
@TestPropertySource("classpath:server-config-test.properties")
public class BindingPropertiesToUserDefinedPOJOUnitTest {
@Autowired
private ServerConfig serverConfig;
@Test
void givenUserDefinedPOJO_whenBindingPropertiesFile_thenAllFieldsAreSet() {
assertEquals("192.168.0.1", serverConfig.getAddress().getIp());
Map<String, String> expectedResourcesPath = new HashMap<>();
expectedResourcesPath.put("imgs", "/root/imgs");
assertEquals(expectedResourcesPath, serverConfig.getResourcesPath());
}
}
이 테스트에서는 다음 어노테이션을 사용했습니다.
- @ExtendWith – Spring의 TestContext 프레임 워크를 JUnit5와 통합
- @EnableConfigurationProperties – @ConfigurationProperties Bean (이 경우 ServerConfig Bean)에대한 지원을 사용합니다.
- @TestPropertySource – 기본 application.properties 파일을 재정의하는 테스트 파일을 지정합니다.
4. @ConfigurationProperties 에 @Bean 메소드
구성 빈을 생성하는 또 다른 방법은 @Bean 메소드 에 @ConfigurationProperties 어노테이션을 사용하는 것 입니다.
예를 들어, 다음 getDefaultConfigs () 메소드는 ServerConfig 구성 Bean을 작성합니다 .
@Configuration
public class ServerConfigFactory {
@Bean(name = "default_bean")
@ConfigurationProperties(prefix = "server.default")
public ServerConfig getDefaultConfigs() {
return new ServerConfig();
}
}
보시다시피 , ServerConfig 클래스 자체 를 편집하지 않고도 getDefaultConfigs () 메서드에서 @ConfigurationProperties 를 사용하여 ServerConfig 인스턴스 를 구성 할 수 있습니다. 이는 액세스가 제한된 외부 타사 클래스로 작업 할 때 특히 유용 할 수 있습니다.
다음으로 샘플 외부 속성을 정의 해 보겠습니다.
server.default.address.ip=192.168.0.2
마지막으로 Spring에 ApplicationContext를 로드 할 때 ServerConfigFactory 클래스 를 사용하도록 지시하기 위해 (따라서 구성 빈을 생성) 테스트 클래스에 @ContextConfiguration 어노테이션을 추가합니다 .
@ExtendWith(SpringExtension.class)
@EnableConfigurationProperties(value = ServerConfig.class)
@ContextConfiguration(classes = ServerConfigFactory.class)
@TestPropertySource("classpath:server-config-test.properties")
public class BindingPropertiesToBeanMethodsUnitTest {
@Autowired
@Qualifier("default_bean")
private ServerConfig serverConfig;
@Test
void givenBeanAnnotatedMethod_whenBindingProperties_thenAllFieldsAreSet() {
assertEquals("192.168.0.2", serverConfig.getAddress().getIp());
// other assertions...
}
}
5. 속성 유효성 검사
Spring Boot에서 빈 유효성 검사 를 활성화하려면 최상위 클래스에 @Validated 어노테이션을 추가해야합니다 . 그런 다음 필요한 javax.validation 제약 조건을 추가합니다 .
@Configuration
@ConfigurationProperties(prefix = "validate")
@Validated
public class MailServer {
@NotNull
@NotEmpty
private Map<String, @NotBlank String> propertiesMap;
@Valid
private MailConfig mailConfig = new MailConfig();
// getters and setters
}
마찬가지로 MailConfig 클래스에도 몇 가지 제약이 있습니다.
public class MailConfig {
@NotBlank
@Email
private String address;
// getters and setters
}
유효한 데이터 세트 제공 :
validate.propertiesMap.first=prop1
validate.propertiesMap.second=prop2
validate.mail_config.address=user1@test
응용 프로그램이 정상적으로 시작되고 단위 테스트가 통과됩니다.
@ExtendWith(SpringExtension.class)
@EnableConfigurationProperties(value = MailServer.class)
@TestPropertySource("classpath:property-validation-test.properties")
public class PropertyValidationUnitTest {
@Autowired
private MailServer mailServer;
private static Validator propertyValidator;
@BeforeAll
public static void setup() {
propertyValidator = Validation.buildDefaultValidatorFactory().getValidator();
}
@Test
void whenBindingPropertiesToValidatedBeans_thenConstrainsAreChecked() {
assertEquals(0, propertyValidator.validate(mailServer.getPropertiesMap()).size());
assertEquals(0, propertyValidator.validate(mailServer.getMailConfig()).size());
}
}
반면에 유효하지 않은 속성을 사용하면 Spring은 start-up에서 IllegalStateException 을 발생 시킵니다.
예를 들어 다음과 같은 잘못된 구성을 사용합니다.
validate.propertiesMap.second=
validate.mail_config.address=user1.test
다음 오류 메시지와 함께 응용 프로그램이 실패합니다.
Property: validate.propertiesMap[second]
Value:
Reason: must not be blank
Property: validate.mailConfig.address
Value: user1.test
Reason: must be a well-formed email address
통지 우리가 사용했던 @Valid를 온 mailConfig의 수 있도록 필드 MailConfig의 경우에도 제약이 체크 validate.mailConfig.address가 정의되지 않았습니다. 그렇지 않으면 Spring은 mailConfig 를 null로 설정 하고 응용 프로그램을 정상적으로 시작합니다.
6. 속성 변환
Spring Boot 속성 변환을 통해 일부 속성을 특정 유형으로 변환 할 수 있습니다.
이 섹션에서는 Spring의 내장 변환을 사용하는 구성 클래스를 테스트하는 것으로 시작합니다. 그런 다음 직접 만든 사용자 지정 변환기를 테스트합니다.
6.1. Spring Boot의 기본 변환
다음 데이터 크기 및 기간 속성을 고려해 보겠습니다.
# data sizes
convert.upload_speed=500MB
convert.download_speed=10
# durations
convert.backup_day=1d
convert.backup_hour=8
Spring Boot는 이러한 속성을 PropertyConversion 구성 클래스에 정의 된 일치하는 DataSize 및 Duration 필드에 자동으로 바인딩합니다 .
@Configuration
@ConfigurationProperties(prefix = "convert")
public class PropertyConversion {
private DataSize uploadSpeed;
@DataSizeUnit(DataUnit.GIGABYTES)
private DataSize downloadSpeed;
private Duration backupDay;
@DurationUnit(ChronoUnit.HOURS)
private Duration backupHour;
// getters and setters
}
이제 변환 결과를 확인하겠습니다.
@ExtendWith(SpringExtension.class)
@EnableConfigurationProperties(value = PropertyConversion.class)
@ContextConfiguration(classes = CustomCredentialsConverter.class)
@TestPropertySource("classpath:spring-conversion-test.properties")
public class SpringPropertiesConversionUnitTest {
@Autowired
private PropertyConversion propertyConversion;
@Test
void whenUsingSpringDefaultSizeConversion_thenDataSizeObjectIsSet() {
assertEquals(DataSize.ofMegabytes(500), propertyConversion.getUploadSpeed());
assertEquals(DataSize.ofGigabytes(10), propertyConversion.getDownloadSpeed());
}
@Test
void whenUsingSpringDefaultDurationConversion_thenDurationObjectIsSet() {
assertEquals(Duration.ofDays(1), propertyConversion.getBackupDay());
assertEquals(Duration.ofHours(8), propertyConversion.getBackupHour());
}
}
6.2. 맞춤형 변환기
이제 convert.credentials 속성 을 변환한다고 가정 해 보겠습니다 .
convert.credentials=user,123
다음 Credential 클래스로 :
public class Credentials {
private String username;
private String password;
// getters and setters
}
이를 위해 사용자 지정 변환기를 구현할 수 있습니다.
@Component
@ConfigurationPropertiesBinding
public class CustomCredentialsConverter implements Converter<String, Credentials> {
@Override
public Credentials convert(String source) {
String[] data = source.split(",");
return new Credentials(data[0], data[1]);
}
}
마지막으로 PropertyConversion 클래스에 Credentials 필드를 추가해 보겠습니다 .
public class PropertyConversion {
private Credentials credentials;
// ...
}
우리에 SpringPropertiesConversionUnitTest 테스트 클래스, 우리는 또한 추가 할 필요가 @ContextConfiguration을 Spring의 컨텍스트에서 사용자 정의 변환기를 등록 :
// other annotations
@ContextConfiguration(classes=CustomCredentialsConverter.class)
public class SpringPropertiesConversionUnitTest {
//...
@Test
void whenRegisteringCustomCredentialsConverter_thenCredentialsAreParsed() {
assertEquals("user", propertyConversion.getCredentials().getUsername());
assertEquals("123", propertyConversion.getCredentials().getPassword());
}
}
이전 어설 션에서 알 수 있듯이 Spring은 사용자 정의 변환기를 사용하여 convert.credentials 속성을 Credentials 인스턴스 로 구문 분석했습니다 .
7. YAML 문서 바인딩
계층 적 구성 데이터의 경우 YAML 구성 이 더 편리 할 수 있습니다. 또한 YAML은 동일한 문서 내에서 여러 프로필 정의를 지원합니다.
src / test / resources / 아래에 있는 다음 application.yml 은 ServerConfig 클래스에 대한 "테스트"프로필을 정의합니다 .
spring:
config:
activate:
on-profile: test
server:
address:
ip: 192.168.0.4
resources_path:
imgs: /etc/test/imgs
---
# other profiles
결과적으로 다음 테스트가 통과됩니다.
@ExtendWith(SpringExtension.class)
@ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class)
@EnableConfigurationProperties(value = ServerConfig.class)
@ActiveProfiles("test")
public class BindingYMLPropertiesUnitTest {
@Autowired
private ServerConfig serverConfig;
@Test
void whenBindingYMLConfigFile_thenAllFieldsAreSet() {
assertEquals("192.168.0.4", serverConfig.getAddress().getIp());
// other assertions ...
}
}
사용 된 어노테이션에 대한 몇 가지 참고 사항 :
- @ContextConfiguration (initializers = ConfigDataApplicationContextInitializer.cla ss) – application.yml 파일을 로드 합니다.
- @ActiveProfiles ( "test") –이 테스트 중에 "test"프로필이 사용되도록 지정합니다.
마지막으로 @ProperySource 도 @TestProperySource 도 .yml 파일 로드를 지원 하지 않는다는 점에 유의 하세요 . 따라서 항상 application.yml 파일 내에 YAML 구성을 배치해야 합니다 .
8. @ConfigurationProperties 구성 재정의
때로는 특히 테스트 할 때 @ConfigurationProperties 에 의해로드 된 구성 속성 을 다른 데이터 세트 로 재정의 하고 싶을 수 있습니다 .
이전 예제에서 살펴본 것처럼 @TestPropertySource ( "path_to_new_data_set") 를 사용하여 전체 원래 구성 ( / src / main / resources 아래) 을 새 구성으로 바꿀 수 있습니다 .
또는 @TestPropertySource 의 속성 속성을 사용하여 원래 속성 중 일부를 선택적으로 대체 할 수도 있습니다 .
이전에 정의 된 validate.mail_config.address 속성을 다른 값 으로 재정의한다고 가정 합니다. 우리가해야 할 일은 @TestPropertySource로 테스트 클래스에 어노테이션을 달고 속성 List을 통해 동일한 속성에 새 값을 할당하는 것입니다 .
@TestPropertySource(properties = {"validate.mail_config.address=new_user@test"})
결과적으로 Spring은 새로 정의 된 값을 사용합니다.
assertEquals("new_user@test", mailServer.getMailConfig().getAddress());
9. 결론
이 사용방법(예제)에서는 @ConfigurationProperties 어노테이션을 사용하여 .properties 및 .yml 구성 파일 을로드 하는 다양한 유형의 구성 클래스를 테스트하는 방법을 살펴 보았습니다 .