Gradle TestKitに触れてみる

に公開

背景

  • DroidKaigi2025で@RyuNen344さんのGradleのセッションを聴いた。

https://x.com/RyuNen344/status/1966398694544290232

https://speakerdeck.com/ryunen344/cache-me-if-you-can

  • Gradleを雰囲気で書きがちなのでユニットテストなりで検証可能な形でタスクを組めると嬉しいなーと思いポストしたところ、テストフレームワーク自体は普通にあるらしいことを教えていただいた。

https://x.com/RyuNen344/status/1966416520063705292

  • せっかくなので触れてみる。

資料

触れてみた

1. 環境設定

  • IntelliJ IDEAで新規プロジェクトを作成する。
  • gradleTestKit() を依存に追加する。
dependencies {
    ...
    testImplementation(gradleTestKit())
}
  • テストフレームワークの依存がなければ適当に追加する。
    • 新規プロジェクト作成だとデフォルトでJUnit5などが使える状態になっているような気がする。

2. サンプル写経 (in Kotlin/kts)

import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class BuildLogicFunctionalTest {
    @TempDir lateinit var testProjectDir: File

    private lateinit var settingsFile: File
    private lateinit var buildFile: File

    @BeforeEach
    fun setup() {
        settingsFile = File(testProjectDir, "settings.gradle.kts")
        buildFile = File(testProjectDir, "build.gradle.kts")
    }

    @Test
    fun testHelloWorldTask() {
        settingsFile.writeText("rootProject.name = \"hello-world\"")
        val buildFileContent = """
            task("helloWorld") {
                doLast {
                    println("Hello, World!")
                }
            }
        """.trimIndent()
        buildFile.writeText(buildFileContent)

        val result = GradleRunner.create()
            .withProjectDir(testProjectDir)
            .withArguments("helloWorld")
            .build()

        assertTrue(result.output.contains("Hello, World!"))
        assertEquals(TaskOutcome.SUCCESS, result.task(":helloWorld")?.outcome)
    }
}

3. ファイル出力のテスト

  • タスク外で定義したプロパティを入力としてtxtファイルを出力するタスクのテスト。
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class CalculateSumOfRangeTest {
    @TempDir
    lateinit var testProjectDir: File
    private lateinit var buildFile: File

    @BeforeEach
    fun setup() {
        buildFile = File(testProjectDir, "build.gradle.kts")
    }

    @Test
    fun testCalculateSumOfRangeTask() {
        val buildFileContent = """
            val rangeMax = 100
            task("calculateSumOfRange") {
                inputs.property("rangeMax", rangeMax)

                val outputFile = file("result.txt")
                outputs.file(outputFile)

                doLast {
                    println("Calculating...")
                    val sum = (1..rangeMax).sum()
                    val result = "Sum from 1 to ${'$'}rangeMax is ${'$'}sum"
                    println(result)
                    outputFile.writeText(result)
                }
            }
        """.trimIndent()
        buildFile.writeText(buildFileContent)

        val result = GradleRunner.create()
            .withProjectDir(testProjectDir)
            .withArguments("calculateSumOfRange")
            .build()

        assertTrue(result.output.contains("Calculating..."))
        assertTrue(result.output.contains("Sum from 1 to 100 is 5050"))
        assertEquals(TaskOutcome.SUCCESS, result.task(":calculateSumOfRange")?.outcome)
        val outputFile = File(testProjectDir, "result.txt")
        assertTrue(outputFile.exists())
        assertEquals("Sum from 1 to 100 is 5050", outputFile.readText())
    }
}

感想

  • Gradleのテストを書くのは割と簡単そう。
  • TaskやBuildResultへの理解を深めるともう少し捗りそう。

Discussion