[ZIO] .conf 변수 불러오기 - Config

Sangwoo Park·2023년 9월 16일
2

개요

프로젝트를 하다 보면 API Key와 같은 민감한 정보들을 따로 관리하는 파일에 저장하고 앱에서 불러와 사용하는 경우가 있다.

테스트 코드에서 이를 불러오는 테스트를 작성해 보았다.

1. 테스트 코드 내에 직접 세팅하기

case class MyConfig(value: Option[String])

object MyConfig {
  val config: Config[MyConfig] = DeriveConfig.deriveConfig[MyConfig].nested("my", "env")
}

object ConfigSpec extends ZIOSpecDefault {

  val testConfigProviderFromMap: ZLayer[Any, Nothing, Unit] =
    Runtime.setConfigProvider(
      ConfigProvider
        .fromMap(Map("my.env.value" -> "this is from map")))

  override def spec: Spec[TestEnvironment with Scope, Any] =
    suite("config from map")(
      test("fetch value from map") {
        for {
          config <- ZIO.config[MyConfig](MyConfig.config)
        } yield assertTrue(config.value.contains("this is from map"))
      }
    ).provideLayer(testConfigProviderFromMap)
}

위의 코드에서 ConfigProvider 를 test suite 에 provideLayer 를 통해 제공해 준다.
ConfigProvider.fromMap() 메서드에 Map 형태로 세팅해서 사용할 수 있다.

2. 파일에서 불러오기

# conf/application.conf
my.env {
    value = "I am a value from conf/application.conf"
}

# test/resources/application.conf
my.env {
    value2 = "I am a value from test/resources/application.conf"
}

# main/resources/application.conf
my.env {
    value3 = "I am a value from main/resources/application.conf"
}

프로젝트 내의 각 경로에 위와 같이 .conf 파일을 준비해둔다.

case class MyConfig(value: Option[String], value2: Option[String], value3: Option[String], nothing: Option[String])

object MyConfig {
  val config: Config[MyConfig] = DeriveConfig.deriveConfig[MyConfig].nested("my", "env")
}

object ConfigSpec extends ZIOSpecDefault {

  private val configProvider: ConfigProvider = TypesafeConfigProvider
    .fromHoconFilePath("conf/application.conf") // 여기에서 먼저 찾고
    .orElse(TypesafeConfigProvider.fromResourcePath()) // 그 다음 여기에서 찾기

  val testConfigProviderFromConfFile: ZLayer[Any, Nothing, Unit] =
    Runtime.setConfigProvider(configProvider)

  override def spec: Spec[TestEnvironment with Scope, Any] =
    suite("config from conf file")(
      test("fetch value from  conf/application.conf") {
        for {
          config <- ZIO.config[MyConfig](MyConfig.config)
        } yield assertTrue(config.value.contains("I am a value from conf/application.conf"))
      },
      test("fetch value from test/resources/application.conf") {
        for {
          config <- ZIO.config[MyConfig](MyConfig.config)
        } yield assertTrue(config.value2.contains("I am a value from test/resources/application.conf"))
      },
      test("fetch value from main/resources/application.conf") {
        for {
          config <- ZIO.config[MyConfig](MyConfig.config)
        } yield assertTrue(config.value3.contains("I am a value from main/resources/application.conf"))
      },
      test("fetch value doesn't exist") {
        for {
          config <- ZIO.config[MyConfig](MyConfig.config)
        } yield assertTrue(config.nothing.isEmpty)
      },
    ).provideLayer(testConfigProviderFromConfFile)
}

테스트코드를 보면 config 값을 찾는 순서는 아래와 같다.
1. configProvider 에 지정해 둔 대로 "conf/application.conf" 에서 먼저 값을 찾는다.
2. 없으면 "test/resources/application.conf" 에서 값을 찾는다.
3. 없으면 "main/resources/application.conf" 에서 값을 찾는다.
4. 없으면 없는것으로 핸들링한다.


결론

테스트 코드에서 환경변수를 원하는 대로 세팅해서 테스트의 자유도를 높일 수 있게 되었다.

profile
going up

0개의 댓글