きり丸の技術日記

技術検証したり、資格等をここに残していきます。

SpringのDisabledIfを素振りする

条件によってはテストを実行しないアノテーション、JUnit5DisabledIfだけでなく、SpringDisabledIfもあります。

基本的にはJUnit5DisabledIfシリーズで十分なことが多いのですが、Spring側で用意されているものも素振りします。

環境

  • Java
    • 17
  • SpringBootTest
    • 2.7.4

前提

設定ファイルの準備

SpringDisabledIfを使用する最大のメリットは、設定ファイルによって挙動を変更できるところです。そのため、application.ymlを定義します。

app:
  config:
    appName: "Kirimaru"
    local: "true"

テストクラスのセットアップ

テストで設定ファイルを読み込めるようにします。

// 設定ファイルを読み込むアノテーションとinitializers
@SpringJUnitConfig(initializers = ConfigDataApplicationContextInitializer.class)

他にも設定ファイルを読み込めるのであればSpringBootTest等々のアノテーションでも問題ありません。ただ、ユニットテストレベルでは不要なDI等々も行ってしまうので、SpringJUnitConfigのほうが早く起動できます。

@SpringBootTest

対応

Spring機能を使用したいので、loadContexttrueを設定します。

${path}

${path}を使用すると、設定ファイルの値を読み込めます。なお、読み込んだ値がtruefalseである必要があります。先ほどapp.config.localtrueを設定しているので、次のテストは動かないように制御できます。

@DisabledIf(value = "${app.config.local}", loadContext = true)
@Test
void test_01() {
  fail();
}

#{expression}

#{expression}を使用すると、中に条件式を記載できます。Springで設定ファイルを読み込むクラスはEnvironmentクラスです。Environmentクラスを利用して、app.config.appNameの値がkirimaruのときに、テストが動かないように制御するには次の式を使用します。

@DisabledIf(
  value = "#{environment.getProperty('app.config.appName').equalsIgnoreCase('kirimaru')}",
  loadContext = true
)
@Test
void test_02() {
  fail();
}

なお、#{}内部で${}は使用できないようです。できるのかもしれませんが、私には理解できませんでした。似たような書き方を聞いている掲示板はあるのですが、解決にはいたっていないようです。

ログを見る限り、app.config.appNameKirimaruは読み込めているのですが、Kirimaruを元にBean名を探しているようでした。

@DisabledIf(value = "#{${app.config.appName}.equalsIgnoreCase('kirimaru')}", loadContext = true)
org.junit.jupiter.engine.execution.ConditionEvaluationException: Failed to evaluate condition [org.springframework.test.context.junit.jupiter.DisabledIfCondition]: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'Kirimaru' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?

備考

JUnit5DisabledIfシリーズも調べるとおもしろいので、ぜひ興味があるときに調べてみてください。

org.junit.jupiter.apiの5.8.2には次のシリーズがありました。

  • DisabledIf
  • DisabledIfEnvironmentVariable
  • DisabledIfSystemProperty
  • DisabledOnJre
  • DisabledOnOs
  • DisabledForJreRange
  • および、上記とは逆のEnabledIfシリーズ

適切ではないですがローカルで動いてCI上で落ちるテストがある場合は、@DisabledOnOs(OS.LINUX)のように回避することもあります。

ソースコード

終わりに

SpringDisabledIfが便利に使えそうだったのですが、検証に時間がかかってしまいました。loadContexttrueにする必要があったり、SpEL式がうまく書けなかったり。

これを覚えたことで今後回避したいアノテーションを作るときには、ちょっとした作り込みをする必要がなくなったので、未来の工数を大きく削減できました。

特定の環境では動かしたくないテストは大量にあるので、今後も活用していきたいです。

参考情報

類似記事