우아한 프로그래밍
article thumbnail

구조

TestServiceTest.java

package com.company.slot.oasis.api.slot.service;

import com.company.slot.oasis.api.config.TestConfig;
import com.company.slot.oasis.api.config.YamlPropertySourceFactory;
import com.company.slot.oasis.api.test.domain.TestService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;


@ExtendWith(SpringExtension.class)
//@TestPropertySource(locations = "classpath:application-test.yml")
//@TestPropertySource(properties = {"spring.config.location = classpath:application-test.yml"})
//@TestPropertySource(properties = {"classpath:/application-test.yml"})
//@TestPropertySource("classpath:application-test.yml")
@TestPropertySource(locations = "classpath:application-test.yml", factory = YamlPropertySourceFactory.class)
@ContextConfiguration(classes = TestConfig.class)
@EnableConfigurationProperties
class TestServiceTest {

    @Autowired
    private TestService testService;

    @Test
    @DisplayName("테스트 서비스에 Prop이 잘 주입되었는지 확인")
    void createSlot() {
        assertThat(testService.getValue()).isEqualTo("test");
    }

}

application-test.yml

spring:
  config:
    activate:
      on-profile: test

  datasource:
    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL
    driver-class-name: org.h2.Driver
    username: sa
    password:
  jpa:
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
        format_sql: true
        globally_quoted_identifiers: true
    show-sql: true
    generate-ddl: true
    database-platform: org.hibernate.dialect.MySQL8Dialect
    database: h2
  h2:
    console:
      enabled: true


test:
  value: test

TestConfig.java

@Configuration
public class TestConfig {

    @Autowired
    private Environment env;

    @Bean
    public TestProp testProp() {
        return new TestProp();
    }

    @Bean
    public TestService testService() {
        return new TestService(testProp());
    }

}

TestServiceTest에서 @TestPropertySource을 이용해서 Property소스를 읽으려고 했습니다.
경로는 잘 찾더라구요.

문제는 아래와 같이 구성하면 구성하게 되면 .yml 형태로 읽는 것이아닌 .properties 형태로 읽게 됩니다.

@TestPropertySource(locations = "classpath:application-test.yml")

그래서 프로퍼티를 읽고나서 test.value 값이 존재 하지 않습니다.
test라는 값은 존재합니다.
value라는 값도 존재합니다.

즉 따로 국밥처럼 .yml이 아닌 .properties 형태로 읽힌것입니다.

많은 블로그들을 참조했더니 아래 처럼 하라고 하더군요

@TestPropertySource(properties = {"spring.config.location = classpath:application-test.yml"})

하지만 정상적으로 동작하지 않습니다.

key가 spring.config.location이고 value가 classpath:application-test.yml인 inline properties가 읽혀지더군요..

해결방안

그래서 해결 방안이 뭐냐?
간단합니다. 아래와 같이 yml을 읽을 때 팩토리를 등록해서 일도록해주면 됩니다.

그럼 test.value로 접근이 가능해 집니다.

@TestPropertySource(locations = "classpath:application-test.yml", factory = YamlPropertySourceFactory.class)

YamlPropertySourceFactory.java

public class YamlPropertySourceFactory implements PropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(encodedResource.getResource());
        return new PropertiesPropertySource(encodedResource.getResource().getFilename(), factory.getObject());
    }
}
profile

우아한 프로그래밍

@자바조아!

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!