Springのapplication.propertiesを環境毎に分ける

Springのapplication.propertiesはローカル開発環境用、単体テスト用、ステージング環境用、本番環境用などに分ける必要がある。

簡単な分け方として、環境によらず常に同じ値にするものはapplication.propertiesに設定して環境毎に変わるもの(あるいは特定の環境だけ設定値を上書き変更したいもの)はapplication-local.properties, application-production.propertiesなどに設定するとする。application.propertiesにはspring.profiles.active=localを設定して、JavaVMシステムプロパティ(-Dspring.profiles.active)や環境変数(SPRING_PROFILES_ACTIVE)を設定しない限りデフォルトでローカル開発環境で動かすとする。

application.properties

spring.profiles.active=local

common_setting_a=value1
common_setting_b=value2

application-local.properties

env_varing_setting_c=value3
env_varing_setting_d=value4

※もっともおすすめの方法として、後にこの書き方を少し変更するため注意

IntelliJ IDEAからアプリを実行する

mainメソッドの実行ボタンをクリックして「Modify Run Configuration」を開き、VM optionsかEnvironment variablesに特定の環境を設定すれば、その環境に対応したプロパティファイルが読み込まれる。

ただ、spring.profiles.activeを設定しているので、IntelliJ IDEAからローカルで開発を行う分には「Modify Run Configuration」で設定する必要がない。

IntelliJ IDEAからJUnitを実行する

IntelliJ IDEAからテスト環境に対応したプロパティファイルを読み込んだ上でJUnitを実行する方法を考える。

コマンドラインから実行する場合はJavaVMシステムプロパティをオプションとして渡せば問題なく実行できるが、IntelliJ IDEAの実行ボタンから実行する場合に、どのようにJavaVMシステムプロパティを渡せばよいかが一見してわからない。

application-test.propertiesとspring.profiles.active

一つ目の方法は、まずapplication-test.propertiesを用意する。

mainメソッドの「Modify Run Configuration」と同様にJUnitの「Modify Run Configuration」のVM optionsかEnvironment variablesでapplication-test.propertiesを読み込むようにすることができる。

しかし、JUnitの各テストクラス及び各テストメソッドごとにConfigurationがあるため、全部に設定することは現実的ではない(統一的に設定する方法は見つけられず、また存在しないはず)。

対応策として、application.propertiesのspring.profiles.activetestに設定し、通常のローカル開発でもVM optionsかEnvironment variablesを設定するというのがある。アプリ起動のConfigurationは一箇所なのに対してJUnitのConfigurationがテスト毎のため、JUnitのプロパティをデフォルトにしてしまうということだ。

デメリット

この方法のデメリットは、デフォルトがローカル環境ではなくテスト環境というのが直感的ではないという点。

application.propertiesをtest/resourcesにおく

二つ目の方法は、テスト専用のapplication.propertiesをtest/resourcesに置く。

JUnit実行時にはtest/resources/application.propertiesが優先して読み込まれるため、「Modify Run Configuration」のVM optionsかEnvironment variablesの設定は必要ない。

デメリット

この方法のデメリットは、プロダクションコードの方は共通設定をapplication.propertiesに書き、環境毎の設定をapplication-local.properties等に書くというように分離していたのを、JUnitのapplication.propertiesは全て一ファイルに書かなければいけない点。

spring.profiles.groupを使ってデメリットを解消する

spring.profiles.groupを使ってデメリットを解消でき、もっともおすすめできる構成となる。

spring.profiles.group

簡単な分け方として、環境によらず常に同じ値にするものはapplication.propertiesに設定して環境毎に変わる値にするもの(あるいは特定の環境だけ設定値を上書き変更したいもの)はapplication-local.properties, application-production.propertiesなどに設定していた。

これをspring.profiles.groupを使ってもう少し整理する。

application.propertiesは、デフォルトでアクティブにしたいものを決めるためにspring.profiles.activeがある点は変わらないが、その他の共通設定はapplication-common.propertiesに移設する。application-common.propertiesはspring.profiles.groupを使ってどの環境でも読み込むようにする。

application.properties

spring.profiles.active=local-group
spring.profiles.group.local-group=common,local
spring.profiles.group.production-group=common,production

application-common.properties

common_setting_a=value1
common_setting_b=value2

application-local.properties

env_varing_setting_c=value3
env_varing_setting_d=value4
test/resources/application.propertiesからmain/resources/application-common.propertiesを読み込む

test/resources/application.propertiesからmain/resources/application-common.propertiesを読み込むことができる。test/resources/application.propertiesではapplication-common.propertiesとテスト専用設定ファイルを読み込むようにtest-groupを定義して、spring.profiles.activetest-groupに設定する。

test/resources/application.properties

spring.profiles.active=test-group
spring.profiles.group.test-group=common,test

test/resources/application-test.properties

env_varing_setting_c=testValue3
env_varing_setting_d=testValue4

ちなみにapplication-test.propertiesはtest/resourcesではなくmain/resourcesに配置してもいい(application-common.propertiesをtest/resources/application.propertiesが読み込めるのと同様に、main/resources/application-test.propertiesも読み込めるため)。

application-local.propetiesとapplication-test.propertiesの構造はほぼ同じになるだろうから、同じディレクトリにおいたほうがいいかもしれない。

main/resources/application-test.properties

env_varing_setting_c=testValue3
env_varing_setting_d=testValue4

GradleのtestメソッドでjvmArgsを設定する

Gradleのtestメソッド内で強制的にjvmArgs += ['-Dspring.profiles.active=test']とする方法もある。

問題なく動くが、力技なのであまり勧めない。

まとめ

共通設定部分を記載するapplication-common.propertiesを用意するとspring.profiles.groupを定義する必要もでるため、プロパティファイルの読み方が若干難しくなる。しかし、設定ファイルの整理整頓具合を考えると、spring.profiles.groupを導入してtest/resources/application.propertiesに以下のみを記載する方法がベストではないかと考える。

spring.profiles.active=test-group
spring.profiles.group.test-group=common,test

環境

  • Java 17
  • Spring Boot 2.6.2
  • IntelliJ IDEA 2021.2.3 (Community Edition)