Kotestシステム拡張(System Extensions)

Kotestのシステム拡張(System Extensions)は、Javaのjava.lang.Systemクラスに関連してシステム呼び出しに対するAssertionを提供する。この拡張は、システム呼び出しの例外をテストし、システム出力やシステム終了のような動作を確認するために使われる。

システム拡張

java.lang.Systemを使用するコードをテストする必要がある場合、Kotestはシステムを変更し、各テスト後に復元できる拡張機能を提供する。この拡張はJVMでのみ使用できる。

この拡張を使用するには、プロジェクトに依存関係を追加する。

io.kotest:kotest-extensions-jvm:${version}

システム環境

システム環境拡張を使用すると、システム環境がどのように動作するかをシミュレートできる。つまり、System.getenv()から得られるものをシミュレートできる。

Kotestは、特定スコープのシステム環境を提供するいくつかの拡張関数を提供している。

withEnvironment("FooKey", "BarValue") {
    System.getenv("FooKey") shouldBe "BarValue" // System environment overridden!
}

この拡張機能では、MapやPairのリストを通じて複数の値を使用することもできる。

withEnvironment(mapOf("FooKey" to "BarValue", "BarKey" to "FooValue")) {
  // Use FooKey and BarKey
}

この関数は、キーと値が現在の環境にない場合は追加し、ある場合は上書きする。関数によって触れられていないキーは環境にそのまま残り、変更されない。

拡張関数の代わりに、提供されているリスナーを使用して、より広いスコープにこの機能を適用することもできる。Spec/テスト単位レベル向けの代替手段と、プロジェクトレベル向けの代替手段がある。

import io.kotest.core.spec.style.FreeSpec
import io.kotest.extensions.system.SystemEnvironmentTestListener
import io.kotest.matchers.shouldBe

class MyTest : FreeSpec() {

    override fun listeners() = listOf(SystemEnvironmentTestListener("foo", "bar"))

    init {
        "MyTest" {
            System.getenv("foo") shouldBe "bar"
        }
    }
}
import io.kotest.core.config.AbstractProjectConfig
import io.kotest.extensions.system.SystemEnvironmentProjectListener

class ProjectConfig : AbstractProjectConfig() {
    override fun listeners() = listOf(SystemEnvironmentProjectListener("foo", "bar"))
}

システムプロパティ拡張

環境拡張と同じ方法で、システムプロパティ(System.getProperties())を上書きできる。

withSystemProperty("foo", "bar") {
    System.getProperty("foo") shouldBe "bar"
}

そして、リスナーとしても提供される。

import io.kotest.core.spec.style.FreeSpec
import io.kotest.extensions.system.SystemPropertyTestListener
import io.kotest.matchers.shouldBe

class MyTest : FreeSpec() {

    override fun listeners() = listOf(SystemPropertyTestListener("foo", "bar"))

    init {
        "MyTest" {
            System.getProperty("foo") shouldBe "bar"
        }
    }
}

システムセキュリティマネージャ

同様に、システムセキュリティマネージャを使用すると、システムセキュリティマネージャ(System.getSecurityManager())を上書きできる。

withSecurityManager(myManager) {
    // Usage of security manager
}

そして、リスナーとしても提供される。

import io.kotest.core.spec.style.FreeSpec
import io.kotest.extensions.system.SecurityManagerListener

class MyTest : FreeSpec() {

    override fun listeners() = listOf(SecurityManagerListener(myManager))

    init {
        // Use my security manager
    }
}

システム終了拡張

コードがSystem.exitを呼び出すかテストしたい場合がある。そのためにシステム終了リスナーを使用できる。リスナーはSystem.exitが呼び出されると例外を投げるため、それを捕捉して確認できる。

import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FreeSpec
import io.kotest.extensions.system.SpecSystemExitListener
import io.kotest.extensions.system.SystemExitException
import io.kotest.matchers.shouldBe

class MyTest : FreeSpec() {

    override fun listeners() = listOf(SpecSystemExitListener)

    init {
        "Catch exception" {
            val thrown: SystemExitException = shouldThrow<SystemExitException> {
                System.exit(22)
            }

            thrown.exitCode shouldBe 22
        }
    }
}

no-stdout/no-stderrリスナー

デバッグメッセージを残していないか、またはロギングに常にロガーを使用しているかを確認したい場合がある。

このために、KotestはNoSystemOutListenerNoSystemErrListenerを提供する。これらのリスナーは、それぞれSystem.outまたはSystem.errへ直接メッセージを出力することを許可しない。

    // In Project or in Spec
    override fun listeners() = listOf(NoSystemOutListener, NoSystemErrListener)

Locale/Timezoneリスナー

一部のコードはデフォルトのLocaleおよびTimezoneを使用したり、それに影響を受けたりする。システムデフォルトを直接操作する代わりに、Kotestに処理させることができる。

withDefaultLocale(Locale.FRANCE) {
  println("My locale is now France! Très bien!")
}

withDefaultTimeZone(TimeZone.getTimeZone(ZoneId.of("America/Sao_Paulo"))) {
  println("My timezone is now America/Sao_Paulo! Muito bem!")
}

そして、リスナーとしても提供される。

// In Project or in Spec
override fun listeners() = listOf(
    LocaleTestListener(Locale.FRANCE),
    TimeZoneTestListener(TimeZone.getTimeZone(ZoneId.of("America/Sao_Paulo")))
)

参照