Kotestリソース(Resources)

Kotestでリソースを自動的に閉じる方法と、テストに必要なファイルやディレクトリを一時的に作成する方法について説明する。

リソースを自動的に閉じる

すべてのテストが実行された後、Kotestにリソースを自動的に閉じさせることができる。

KotestのautoClose関数を使うと、特定のリソースを使用後に自動で解放できるため、リソース管理が簡単になる。主にテストで外部リソースを使う場合に使用され、リソース解放を明示的に処理しなくても自動で処理できる。

たとえば、ファイルやデータベース接続のような外部リソースをテストで使用する場合、そのリソースを使った後は明示的に解放する必要がある。しかしautoCloseを使用すると、テストが終わるとリソースが解放される。

package com.devkuma.kotest.tutorial.resources

import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import java.io.StringReader

class StringTest : StringSpec({

    val reader = autoClose(StringReader("xyz"))

    "test" {
        val text = reader.readText()

        println(text)

        text shouldBe "xyz"
    }
})

この方法で閉じるリソースはjava.lang.AutoCloseableを実装している必要がある。クローズ処理は、最後のSpecインターセプターが返った後、宣言順の逆順で実行される。

一時ファイル

テストでファイルを作成し、テスト後に削除しなければならない場合があるが、手動で削除するとテスト失敗時に問題が起きることがある。

たとえば、テスト中に一時ファイルを作成し、テストが正常に通過した場合はクリーンアップコードが実行されファイルが削除される。しかし、アサーションが失敗したり別のエラーが発生してファイルが削除されなかったりすると、次回実行時にテストに影響を与える古いファイルが残る可能性がある。たとえば、ファイルを上書きできない例外などである。

Kotestは、Specでテスト用一時ファイルを作成するために使えるtempfile()関数を提供しており、この関数で作成したファイルはSpec内のすべてのテスト実行後にKotestが整理する。これにより、テストで一時ファイルの削除を心配する必要がなくなる。

package com.devkuma.kotest.tutorial.resources

import io.kotest.core.spec.style.FunSpec
import io.kotest.engine.spec.tempfile
import io.kotest.matchers.shouldBe
import java.io.FileReader

class TempFileTest : FunSpec({

    val file = tempfile()

    test("a temporary file dependent test") {
        // ファイルパス
        println(file.path)

        // ファイル書き込み
        val text = "Hello, Kotest!"
        file.writeText(text)

        // ファイル読み込み
        val reader = autoClose(FileReader(file))
        reader.readText() shouldBe text
    }
})

一時ディレクトリ

一時ファイルと同じように、tempdir()を使って一時ディレクトリを作成できる。

package com.devkuma.kotest.tutorial.resources

import io.kotest.core.spec.style.FunSpec
import io.kotest.engine.spec.tempdir
import io.kotest.matchers.shouldBe

class TempDirTest : FunSpec({

    val dir = tempdir()

    test("a temporary dir dependent test") {
        println(dir.path)

        dir.isDirectory shouldBe true
    }
})

参照