GeekFactory

int128.hatenablog.com

Gradle TestKitでプラグインをテストする

GradleプラグインのテストにGradle TestKitを利用すると便利です。

何に使うの?

ユニットテストではうまく動いているのに、実際のプロジェクトにプラグインを適用するとうまく動かないことがあります。これはGroovyのバージョンが違うとか、ビルドスクリプトのスコープで暗黙的に定義されている変数があるといったことが原因です。MetaClassやdelegateで特殊なことをしていると起こることがあります。

実際のプロジェクトにプラグインを適用するには、以下の手順が必要になります。

  1. プラグインのJARをビルドする。
  2. プラグインをローカルのMavenリポジトリに配置する。
  3. テスト対象プロジェクトでローカルのMavenリポジトリにあるプラグインを読み込む。
  4. テスト対象プロジェクトでタスクを実行する。

Gradle TestKitを利用すると、以下の手順で済みます。

  1. テスト対象プロジェクトのタスクを実行するテストコードを実行する。

簡単ですね。ただし、Gradle TestKitによるプラグインのテストはGradle 2.13以降で使えます。2.13より前の場合は自分でクラスパスを設定する必要があります。詳しくは下記を参照してください。

https://docs.gradle.org/current/userguide/test_kit.html#sub:test-kit-automatic-classpath-injection

ここでは、実際のプロジェクトにプラグインを適用して期待通りの動作を確認することを受け入れテストと定義します。受け入れテストを実行するには以下が必要です。

  • 受け入れテストのプロジェクト
  • 受け入れテストのテストコード
  • テスト対象プロジェクト

まず、受け入れテストのプロジェクトを見ていきましょう。TestKitを有効にするため java-gradle-plugin を適用します。また、テスト対象のプラグインが別のプロジェクトにある場合は gradlePlugin { pluginSourceSet } で指定します。

// acceptance-test/build.gradle : 受け入れテストのプロジェクト
plugins {
    id 'groovy'
    id 'java-gradle-plugin'
}

repositories {
    jcenter()
}

dependencies {
    testCompile('org.spockframework:spock-core:1.0-groovy-2.4') {
        exclude module: 'groovy-all'
    }
}

gradlePlugin {
    // 親プロジェクトにテスト対象のプラグインがあることを指定します
    pluginSourceSet parent.sourceSets.main
}

受け入れテストのテストコードは以下になります。 withPluginClasspath() を指定すると、プラグインのクラスパスが自動的に追加されるようになります。

// acceptance-test/src/test/groovy/AcceptanceSpec.groovy : 受け入れテストのテストコード
import org.gradle.testkit.runner.GradleRunner
import spock.lang.Specification
import spock.lang.Unroll

class AcceptanceSpec extends Specification {
    @Unroll
    def 'acceptance test should pass'() {
        given:
        def runner = GradleRunner.create()
            .withProjectDir(new File('fixture'))
            .withArguments('test')
            .withPluginClasspath()

        when:
        runner.build()

        then:
        noExceptionThrown()
    }
}

テスト対象プロジェクトは以下になります。ここでは単純にプラグインが存在するかassertしています。

// acceptance-test/fixture/build.gradle : テスト対象プロジェクト
plugins {
    id 'com.example.hello'
}

task test << {
    assert project.plugins.hasPlugin('com.example.hello')
}

応用編

withGradleVersion() を使うと、複数のバージョンでプラグインが動作するかテストできます。SpockのData Driven Testingを使えば簡単に書けます。

        given:
        def runner = GradleRunner.create()
            .withProjectDir(new File('fixture'))
            .withArguments('test')
            .withPluginClasspath()
            .withGradleVersion(gradleVersion)

        where:
        gradleVersion << ['3.1', '2.13']

Gradle Plugin Starterで実際に使っているので参考にしてください。

github.com

まとめ

Gradleのプラグインを実際のプロジェクトに適用して期待通りの動作を確認するにはこれまで面倒な手順が必要でしたが、Gradle TestKitを利用すれば簡単に実現できるようになりました。

Gradle徹底入門 次世代ビルドツールによる自動化基盤の構築

Gradle徹底入門 次世代ビルドツールによる自動化基盤の構築