0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

カスタムGradleプラグインを自動化テストする方法

Last updated at Posted at 2022-06-23

はじめに

カスタムなGradleプラグインを開発するにあたってテストをしたい。どういうコードを書けば自動化テストができるか?その方法を説明します。ちゃんと動くサンプルコード一式を提供します。

Gradle本家プロジェクトによるこの記事に基づいています。

使い方

前提していること

  1. あなたの環境にJava8ないしそれ以降のJava環境がインストール済みであること

  2. macOS v12.4でGradle v7.4.2を使ってこの記事をテストしました。WindowsやLinuxでも問題なく動くはずですが、わたしは試していません。

  3. あなたがJavaプログラミングとGradleの基本を理解していることを前提します。 $ ./gradlw test というコマンドが何をしているかというレベルの説明は省きます。

サンプルコードをどうやって手に入れるか

あなたがGitHubアカウントを持っているならば、このGitHubレポジトリのトップ the top page を開き、Use this template をクリックしましょう。あなたのGitHubアカウントの中に新しいレポジトリとして本レポジトリの複製を作ることができます。

あなたがGitHubアカウントを持っていないならば、 Releasesページ を開き、最新の"Source code" のzipをダウンロードしてください。

自動化テストをどうやって実行するか

サンプルとして提供された自動化テストを走らせるにはコマンドラインで下記のように操作します。

console

$ basename $(pwd)
TestingGradlePlugins-revised
$ cd url-verifier-plugin
$ ./gradlew clean check
Starting a Gradle Daemon (subsequent builds will be faster)
Type-safe dependency accessors is an incubating feature.
> Task :clean UP-TO-DATE
> Task :compileJava
> Task :compileGroovy NO-SOURCE
> Task :pluginDescriptors
> Task :processResources
> Task :classes
> Task :compileTestJava NO-SOURCE
> Task :compileTestGroovy
> Task :processTestResources NO-SOURCE
> Task :testClasses
> Task :test
> Task :compileFunctionalTestJava NO-SOURCE
> Task :compileFunctionalTestGroovy
> Task :processFunctionalTestResources NO-SOURCE
> Task :functionalTestClasses
> Task :pluginUnderTestMetadata
> Task :functionalTest
> Task :compileIntegrationTestJava NO-SOURCE
> Task :compileIntegrationTestGroovy
> Task :processIntegrationTestResources NO-SOURCE
> Task :integrationTestClasses
> Task :integrationTest
> Task :validatePlugins
> Task :check

BUILD SUCCESSFUL in 32s
12 actionable tasks: 11 executed, 1 up-to-date

:url-verifier-plugin:check タスクを実行するとそれを基点として`:url-verifier-plugin:test`タスクと :url-verifier-plugin:intergrationTest タスクと :url-verifier-plugin:functionalTest が実行されます。これら3つのタスクがカスタムGradleプラグイン org.myorg.url-verifier のための自動化テストです.

もうひとつ、テストのやり方の例があります。

console

$ cd ../include-plugin-build
$ ./gradlew verifyUrl
> Task :url-verifier-plugin:compileJava UP-TO-DATE
> Task :url-verifier-plugin:compileGroovy NO-SOURCE
> Task :url-verifier-plugin:pluginDescriptors UP-TO-DATE
> Task :url-verifier-plugin:processResources UP-TO-DATE
> Task :url-verifier-plugin:classes UP-TO-DATE
> Task :url-verifier-plugin:jar

> Task :verifyUrl
Successfully resolved URL 'https://www.google.com/'

BUILD SUCCESSFUL in 2s
5 actionable tasks: 2 executed, 3 up-to-date

:invlude-plugin-build プロジェクトの :verifyUrl タスクは url-verify-plugin プロジェクトで開発された カスタムGradleプラグイン org.myorg.url-verifier を実行して、その結果を検証します。

ディレクトリ構造

このレポジトリには根ディレクトリとして TestingGradlePlugins-revised ディレクトリがあります。その下にディレクトリが二つ(url-verifier-plugininclude-plugin-build)あって、各々が独立したGradleプロジェクトになっています。.

console

$ basename `pwd`
TestingGradlePlugins-revised
$ tree . -L 2
.
├── README.md
├── include-plugin-build
│   ├── build.gradle
│   ├── gradle
│   ├── gradlew
│   ├── gradlew.bat
│   └── settings.gradle
└── url-verifier-plugin
    ├── build.gradle
    ├── gradle
    ├── gradlew
    ├── gradlew.bat
    ├── settings.gradle
    └── src

ディレクトリ TestingGradlePlugins-revised がGitレポジトリのルートであり、GitHubレポジトリ https://github.com/kazurayam/TestingGradlePlugins-revised に格納されていて、その下にある2つのGradleプロジェクトを同期を保ったままバージョン管理することができています。

第一のGradleプロジェクト url-verifier-plugin でカスタムGradleプラグインを開発します。 url-verifier-plugin プロジェクトは自己完結的であって、隣の include-plugin-build プロジェクトにはまったくつながりがありません。

第二のGradleプロジェクト include-plugin-build は隣の`url-veirifer-plugin` プロジェクトで開発されたカスタムGradleプラグインを呼び出して実行します。

GradleのComposite buildというもの

Gradleには Composite builds という用語がある。 include-plugin-build プロジェクトは Composite builds の具体例になっています。ちゃんと動く。

Google検索すれば Composite build とは何か、どうやって作るのか、何に役立つのか、といったことを解説する記事がいくつも見つかります。たとえば

しかしComposite buildsを理解するにはGradleに関する詳細な知識が必要で、正直なところ、わたしはまだ Gradle Composite builds がよくわかっていません。

カスタムGradleプラグインを書く

`url-verifier-plugin`プロジェクトが開発するカスタムGradleプラグインの実装コードをここで示します。

私は "Writing Custom Gradle Plugins", Baeldung を参考にしました。

org.myorg.UrlVerifierPlugin class

UrlVerifierPlugin クラスがカスタムGradleプラグインの本体です。パラメータ url としてURL文字列を受け取ることができます。プラグインは実行されると指定されたURLに対してHTTP GETリクエストを送り、HTTP応答のステータスが200 OKであるかどうかを調べます。もし200ならプラグインは "Successfully resolved URL" と言うメッセージを、さもなければ "Failed to resolve URL" と言うメッセージを標準出力に表示します。

file url-verifier-plugin/src/main/java/org/myorg/UrlVerifierPlugin.java

package org.myorg;

import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.myorg.tasks.UrlVerify;

public class UrlVerifierPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        // add the 'verification' extension object
        UrlVerifierExtension extension =
                project.getExtensions()
                        .create("verification", UrlVerifierExtension.class);
        // create the 'verifyUrl' task
        project.getTasks().register("verifyUrl", UrlVerify.class, task -> {
            task.getUrl().set(extension.getUrl());
        });
    }
}

org.myorg.UrlVerifierExtension class

file url-verifier-plugin/src/main/java/org/myorg/UrlVerifierExtension.java

package org.myorg;

public class UrlVerifierExtension {
    public String url;

    public String getUrl() {
        return url;
    }
}

org.myorg.tasks.UrlVerify class

file url-verifier-plugin/src/main/java/org/myorg/tasks/UrlVerify.java

package org.myorg.tasks;

import org.gradle.api.DefaultTask;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
import org.myorg.http.DefaultHttpCaller;
import org.myorg.http.HttpCallException;
import org.myorg.http.HttpCaller;
import org.myorg.http.HttpResponse;

abstract public class UrlVerify extends DefaultTask {

    @Input
    abstract public Property<String> getUrl();

    public UrlVerify() {
        getUrl().convention("https://docs.gradle.org/current/userguide/testing_gradle_plugins.html");
    }

    @TaskAction
    public void action() throws HttpCallException {
        HttpCaller httpCaller = new DefaultHttpCaller();
        HttpResponse httpResponse = httpCaller.get(this.getUrl().get());
        if (httpResponse.getCode() == 200) {
            System.out.println(String.format("Successfully resolved URL '%s'", getUrl().get()));
        } else {
            System.err.println(String.format("Failed to resolve URL '%s'", getUrl().get()));
        }
    }
}

org.myorg.http.DefaultHttpCaller class

file url-verifier-plugin/src/main/java/org/myorg/http/DefaultHttpCaller.java

package org.myorg.http;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

public class DefaultHttpCaller implements HttpCaller {
    @Override
    public HttpResponse get(String url) throws HttpCallException {
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setConnectTimeout(5000);
            connection.setRequestMethod("GET");
            connection.connect();

            int code = connection.getResponseCode();
            String message = connection.getResponseMessage();
            return new HttpResponse(code, message);

        } catch (IOException e) {
            throw new HttpCallException(String.format("Failed to call URL '%s' via HTTP GET", url), e);
        }
    }
}

org.myorg.http.HttpCaller class

file url-verifier-plugin/src/main/java/org/myorg/http/HttpCaller.java

package org.myorg.http;

public interface HttpCaller {

    HttpResponse get(String url) throws HttpCallException;
}

org.myorg.http.HttpResponse class

file url-verifier-plugin/src/main/java/org/myorg/http/HttpResponse.java

package org.myorg.http;

public class HttpResponse {
    private int code;
    private String message;

    public HttpResponse(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    @Override
    public String toString() {
        return "HTTP " + code + ", Reason: " + message;
    }
}

自動化テストを作る

テストのソースのディレクトリ構造

カスタムGradleプラグインを開発するプロジェクトの名前は url-verifier-plugin です。このプロジェクトにはソースコードを格納するためのディレクトリが4つあります。すなわち

  1. src/main/

  2. src/test/

  3. src/integrationTest/

  4. src/functionalTest/

これらサブディレクトリがGradleのSource Setに対応します。

console

$ basename $(pwd)
url-verifier-plugin
$ tree . -L 3
.
└── src
    ├── functionalTest
    │   └── groovy
    ├── integrationTest
    │   └── groovy
    ├── main
    │   ├── java
    │   └── resources
    └── test
        └── groovy

src/main/ ディレクトリにはカスタムGradleプラグイン本体のJavaソースコードが格納されています。

残り3つのディレクトリには自動化テストのコードが格納されています。

src/test/ ディレクトリには`src/main`のコードをユニット・テストするためのコードが格納されています。

src/integrationTest/ ディレクトリにはインテグレーション・テストのためのコードが格納されています。インテグレーション・テストとはそれを実行するのに他のリソース(`http://`で始まるURLやデータベース)と接続する必要があるテストです。

src/functionalTest/ ディレクトリにはファンクショナル・テストのためのコードが格納されています。ファンクショナル・テストとはテスト対象であるカスタムGradleプラグインを利用者の視点からテストするものです。ファンクショナル・テストはカスタムGradleプラグインを呼び出すような`build.gradle`ファイルを動的に生成し即座に実行します。そしてプラグインからの出力を調べてプラグインの動作を検証します。

カスタムなSource SetとカスタムなTaskを作る

Gradleは Source sets という概念をもっています。Source Setによってプログラムのソースコード群を分類することができます。Source Sets についてわたしは "Gradle Source Sets", Baeldung を参考にしました。

ちなみに url-verifier-plugin プロジェクトは groovy プラグインと java-gradle-plugin プラグインを使っています。

file url-verifier-plugin/build.gradle

plugins {
    id 'groovy'
    id 'java-gradle-plugin'

groovy プラグインを適用することにより、url-verifier-plugin プロジェクトのなかに2つの source sets が自動的につくられます。すなわち maintest です。

main ソースセットは url-verifier-plugin/src/main/ ディレクトリに格納されたソースコードに対応します。そこにはカスタムプラグインのソースがあります。

test ソースセットは url-verifier-plugin/src/test/ ディレクトリに格納されたソースコードに対応します。そこにはユニットテストのソースがあります。

あと2つ、ソースセットを明示的に追加しました。すなわち integrationTestfunctionalTest です。どうやって追加したか、次のコードを参照してください。

file url-verifyer-plugin/build.gradle

def integrationTest = sourceSets.create("integrationTest")
def integrationTestTask = tasks.register("integrationTest", Test) {
    description = "Runs the integration tests."
    testClassesDirs = integrationTest.output.classesDirs
    classpath = integrationTest.runtimeClasspath
    mustRunAfter(tasks.named('test'))
}

def functionalTest = sourceSets.create("functionalTest")
def functionalTestTask = tasks.register("functionalTest", Test) {
    description = "Runs the functional tests."
    group = "verification"
    testClassesDirs = functionalTest.output.classesDirs
    classpath = functionalTest.runtimeClasspath
    mustRunAfter(tasks.named('test'))
}

tasks.named('check') {
    dependsOn(integrationTestTask, functionalTestTask)
}

ついでにカスタムタスク :check を定義しました。:check タスクは :integrationTest タスクと :functionalTest タスクを呼び出します。

java-gradle-pluginプラグインを設定する

ファンクショナル・テスト UrlVerifierPluginFunctionalTest がカスタムGradleプラグインを実行するときに org.gradle.testkit.runner.GradleRunner クラスの助けを必要とします。GradleRunnerクラスは java-gradle-plugin プラグインによって提供されます。ファンクショナル・テストのコードに対して`GradleRunner`クラスをimport可能にするために、1行だけ設定を書く必要があります。

file url-verifier-plugin/build.gradle

gradlePlugin {
    // configure the `java-gradle-plugin` so that it looks at the `sourceSets.functionalTest`
    // to find the tests for the custom plugin.
    testSourceSets(sourceSets.functionalTest)
    // This makes `org.gradle.testkit.runner.GradleRunner` class available to the
    // functionalTest classes.
}

テスト・フレームワーク Spock を使えるようにする

テスト・フレームワーク Spock を使って自動化テストを書くことにしました。もちろんSpockを使わずJUnitやTestNGを使って書くこともできます。お好みで。

url-verifier-plugin/build.gradle ファイルと url-verifier-plugin/settings.gradle にSpockに関する設定を記述しました。

file url-verifier-plugin/build.gradle

dependencies {
    // we will use Spock frame for testing
    testImplementation platform(libs.spock.bom)
    testImplementation libs.spock.core
    integrationTestImplementation platform(libs.spock.bom)
    integrationTestImplementation libs.spock.core
    functionalTestImplementation platform(libs.spock.bom)
    functionalTestImplementation libs.spock.core

platform(…​) とは何でしょうか? Gradle doc, "Sharing dependency versions between projects / Using a platform to control transitive versions"platform(…​) 関する説明があります。

file url-verifier-plugin/settings.gradle

dependencyResolutionManagement {
    versionCatalogs {
        libs {
            version('spock', '2.0-groovy-3.0')
            library('spock-core', 'org.spockframework', 'spock-core').versionRef('spock')
            library('spock-bom', 'org.spockframework', 'spock-bom').versionRef('spock')
        }
    }
}

ここでわたしは "Version Catalog" と呼ばれる表記法をとりました。 "org.spockframework:spock-core:2.0-groovy-3.0" という長い記述に対する短い別名 (libs.spock.core) をVersion Catalogを使って定義しました。別名を使うことにより、2.0-groovy-3.0 というバージョン番号を書くのを1箇所だけにすることができました。

ユニット・テストのコード

org.myorg.http.HttpResponse クラスに対するユニット・テストのコードは下記の通りです。

file url-verifier-plugin/src/test/groovy/org/myorg/http/HttpResponseTest.groovy

package org.myorg.http

import spock.lang.Specification

class HttpResponseTest extends Specification {

    private static final int OK_HTTP_CODE = 200
    private static final String OK_HTTP_MESSAGE = 'OK'

    def "can access information"() {
        when:
        def httpResponse = new HttpResponse(OK_HTTP_CODE, OK_HTTP_MESSAGE)

        then:
        httpResponse.code == OK_HTTP_CODE
        httpResponse.message == OK_HTTP_MESSAGE
    }

    def "can get String representation"() {
        when:
        def httpResponse = new HttpResponse(OK_HTTP_CODE, OK_HTTP_MESSAGE)

        then:
        httpResponse.toString() == "HTTP ${OK_HTTP_CODE}, Reason: ${OK_HTTP_MESSAGE}"
    }
}

HttpResponseTest クラスにメソッドを増やしてもっと網羅的なテストにすることができます。また main ソースセットにある他のクラスに対するユニット・テストを追加することもできます。

インテグレーション・テストのコード

次に示すテストは外部のURL ("https://www.google.com/") にHTTP要求をします。このテストを実行するにはインターネットへの接続が可能な環境が必要であり、かつ外部URLがちゃんと応答してくれることが必要です。これら必要条件が満たされなければこのテストは失敗します。

このように外部リソースに依存するテストを Integration Test と呼び、ユニット・テストから区別することにします。

file url-verifier-plugin/src/integrationTest/groovy/org/myorg/http/DefaultHttpCallerIntegrationTest.groovy

package org.myorg.http

import spock.lang.Specification
import spock.lang.Subject

/**
 * https://docs.gradle.org/current/userguide/testing_gradle_plugins.html
 */
class DefaultHttpCallerIntegrationTest extends Specification {

    @Subject HttpCaller httpCaller = new DefaultHttpCaller()

    def "can make successful HTTP GET call"() {
        when:
        def httpResponse = httpCaller.get("https://www.google.com/")

        then:
        httpResponse.code == 200
        httpResponse.message == 'OK'
    }

    def "throws exception when calling unknown host via HTTP GET"() {
        String url = 'https://www.wedonotknowyou123.com/'

        when:
        httpCaller.get(url)

        then:
        def t = thrown(HttpCallException)
        t.message == "Failed to call URL '${url}' via HTTP GET"
        t.cause instanceof UnknownHostException
    }
}

ファンクショナル・テストのコード

次に示すテストはカスタムGradleプラグインを実行し、プラグインの出力を検証します。

  • テストは一時的ファイルとして build.gradle を生成します。そのビルドはカスタムGradleプラグイン org.myorg.url-verifier をロードします。

  • カスタムGradleプラグインがロードされると自動的に :verifyUrl タスクが追加されます。

  • テストはGradleビルドを実行します。それはあたかも人がコマンドラインで下記のようにコマンドをタイプしたのと同じことです。

$ gradle verifyUrl https://www.google.com/
  • カスタムプラグインが完了したらプラグインの出力をテストが取り出して検証します。

file url-verifier-plugin/src/functionalTest/groovy/org/myorg/UrlVerifierPluginFunctionalTest.groovy

package org.myorg

import org.gradle.testkit.runner.GradleRunner
import spock.lang.Specification
import spock.lang.TempDir

import static org.gradle.testkit.runner.TaskOutcome.SUCCESS

class UrlVerifierPluginFunctionalTest extends Specification {

    @TempDir File testProjectDir
    File buildFile

    def setup() {
        buildFile = new File(testProjectDir, 'build.gradle')
        buildFile << """
            plugins {
                id 'org.myorg.url-verifier'    
            }
        """
    }

    def "can successfully configure URL through extensions and verify it"() {
        buildFile << """
            verification {
                url = 'https://www.google.com/'
            }
        """

        when:
        def result = GradleRunner.create()
                .withProjectDir(testProjectDir)
                .withArguments('verifyUrl')
                .withPluginClasspath()
                .build()

        then:
        result.output.contains("Successfully resolved URL 'https://www.google.com/'")
        result.task(":verifyUrl").outcome == SUCCESS
    }
}

カスタムGradleプラグインを利用する側のプロジェクトの実装例

コマンドラインで次のような操作をしてみましょう。verifyUrl タスクを実行しています。verifyUrl タスクはカスタムGradleプラグイン org.myorg.url-verifier を呼び出しています。

console

$ basename `pwd`
TestingGradlePlugins-revised
$ cd include-plugin-build/
$ ./gradlew verifyUrl

> Task :verifyUrl
Successfully resolved URL 'https://www.google.com/'

BUILD SUCCESSFUL in 1s
5 actionable tasks: 1 executed, 4 up-to-date

カスタムプラグインを利用するプロジェクトはどのように作られているのでしょうか?ファイルが2つあります。

file include-plugin-build/build.gradle

buildscript {
    // declare the output of the plugin development project
    // as a dependency of this consumer project
    dependencies {
        classpath 'org.myorg:url-verifier-plugin'
        // `<group>:<name>` without `<version>`
    }
}

// find the custom plugin by id
apply plugin: 'org.myorg.url-verifier'

verification {
    // give a value to the custom plugin's parameter
    url = 'https://www.google.com/'
}

buildscript {} クロージャがあって、このビルドスクリプトが org.myorg:url-verifier-plugin というgroupとnameをもつライブラリに依存するということを表明しています。それに続く apply plugin がライブラリの中からカスタムプラグイン org.myorg.url-verifier を取り出して利用するぞと表明しています。verifycation { url = '…​' } クロージャはカスタムプラグインが受け取ることのできるパラメータ url に対して具体的な値を与えています。

file include-plugin-build/setting.gradle

// include the build of the plugin development project
includeBuild("../url-verifier-plugin") {
    dependencySubstitution {
        // explicitly load the output of the included build
        // into the consumer project's classpath
        substitute(module("org.myorg:url-verifier"))
    }
}

この settings.gradle ファイルは includeBuilddependencySubstitution 、 substitutemodule などの呪文を使っています。わたしは或る解説記事の一部をコピペして調節しました。このサンプルは実行するとちゃんと動きます。しかしわたしは呪文の意味がまだわかっていません。

別のやり方

url-verifier-plugin プロジェクトが作ったカスタム・プラグインを`include-plugin-build` プロジェクトが実行できるように構成する方法がもう一つあります。org.myorg.url-verifier を含むJARファイルを作って、それをMavenレポジトリにpublishする。publishされたJARファイルを include-plugin-build プロジェクトが参照する、と言うやり方です。maven-publish プラグインを使ってJARを作り mavenLocalレポジトリに publishしましょう。

file url-verifier-plugin/build.gradle

plugins {
    id 'groovy'
    id 'java-gradle-plugin'
    id 'maven-publish'
}

group 'org.myorg'
version '1.2.1'

repositories {
    mavenCentral()
}

そしてコマンドラインで次のようにコマンドを実行する。

$ basename $(pwd)
url-verifier-plugin
$ ./gradlew publishToMavenLocal
...

そうするとJARファイルが作られました。

$ pwd
/Users/kazurayam/.m2/repository/org/myorg/url-verifier-plugin/1.2
$ ls -la
total 32
drwxr-xr-x  5 kazurayam  staff   160  6 22 11:03 .
drwxr-xr-x  7 kazurayam  staff   224  6 22 11:03 ..
-rw-r--r--  1 kazurayam  staff  5840  6 22 11:03 url-verifier-plugin-1.2.jar
-rw-r--r--  1 kazurayam  staff  1916  6 22 11:03 url-verifier-plugin-1.2.module
-rw-r--r--  1 kazurayam  staff   757  6 22 11:03 url-verifier-plugin-1.2.pom

カスタムプラグインを含むJARが mavenLocal レポジトリに作られた後であれば、下記のように設定すればOKです。

file include-plugin-build/build.gradle

buildscript {
    repositories {
        mavenLocal()
    }
    dependencies {
        classpath 'org.myorg:url-verifier-plugin:1.2'
    }
}
apply plugin: 'org.myorg.url-verifier'

verification {
    url = 'https://www.google.com/'
}

file include-plugin-build/settings.gradle

/* I do not use includeBuild */

このやり方はちゃんと動きます。しかしこのやり方には良くないところがある。2つ問題があります。

  1. プラグインのコードを変更した後テストするたびに publishToMavenLocal タスクを繰り返し実行しなければならないのが面倒だ。

  2. プラグインのバージョン番号(1.2)が2箇所に書いてある。url-verifier-plugin/build.gradle ファイルのなかに書いてあるのは当然だが、include-plugin-build/build.gradle ファイルにも書いてあるのがまずい。バージョンを変更しようとする時、片方のファイルだけ修正してもう片方を忘れるリスクがある。

オリジナルをどう手直ししたか

このレポジトリが示すサンプルコードはGradleプロジェクトが公開している下記の記事に基づいています。

この記事のことを指して「オリジナル」と呼ぶことにします。わたしが組み立てたサンプルコードはオリジナルと違うところがいくつかあります。どこを手直ししたのか、下記に列挙します。

Composite projectsの組み立て方

プラグイン利用者側プロジェクトをどうやってプラグイン開発プロジェクトと関連づけるかという問題があります。

オリジナル記事は次のようなコードを示しています。

file include-plugin-build/build.gradle

plugins {
    id 'org.myorg.url-verifier'
}

file include-plugin-build/settings.gradle

pluginManagement {
    includeBuild '../url-verifier-plugin'
}

このやり方は動きませんでした。 いざ動かすと次のようなエラーが発生しました。

$ basename $(pwd)
include-plugin-build
$ gradle verifyUrl

FAILURE: Build failed with an exception.

* Where:
Build file '/Users/kazuakiurayama/tmp/url-verifier-gradle-plugin/include-plugin-build/build.gradle' line: 2

* What went wrong:
Plugin [id: 'org.myorg.url-verifier'] was not found in any of the following sources:

- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Included Builds (None of the included builds contain this plugin)
- Plugin Repositories (plugin dependency must include a version number for this source)
...

わたしは次のように手直ししました。

file include-plugin-build/build.gradle

buildscript {
    // declare the output of the plugin development project
    // as a dependency of this consumer project
    dependencies {
        classpath 'org.myorg:url-verifier-plugin'
        // `<group>:<name>` without `<version>`
    }
}

// find the custom plugin by id
apply plugin: 'org.myorg.url-verifier'

verification {
    // give a value to the custom plugin's parameter
    url = 'https://www.google.com/'
}

file include-plugin-build/settings.gradle

// include the build of the plugin development project
includeBuild("../url-verifier-plugin") {
    dependencySubstitution {
        // explicitly load the output of the included build
        // into the consumer project's classpath
        substitute(module("org.myorg:url-verifier"))
    }
}

この書き方をわたしは
"Gradle plugins and Composite builds" by ncorti という記事で習いました。

integrationTestのクラスがmainソースセットに依存していることの表明

下記のコードを参照のこと。

file url-verifier-plugin/build.gradle

    // let the integrationTest refer to the class files
    // of the `main` sourceSet.
    integrationTestImplementation sourceSets.main.output
}

integrationTest ソースセットのなかのテストclassが
main ソースセットのなかにあるプラグインclassをimportします。だからこの1行が必要になります。この1行が無いと `integrationTest`のコードはコンパイルできません。下記のようなエラーになります。

$ basename $(pwd)
url-verifier-plugin
$ ./gradlew integrationTest

> Task :compileIntegrationTestGroovy
startup failed:
/Users/kazuakiurayama/github/TestingGradlePlugins-revised/url-verifier-plugin/src/integrationTest/groovy/org/myorg/http/DefaultHttpCallerIntegrationTest.groovy: 11: unable to resolve class HttpCaller
 @ line 11, column 5.
       @Subject HttpCaller httpCaller = new DefaultHttpCaller()
       ^

/Users/kazuakiurayama/github/TestingGradlePlugins-revised/url-verifier-plugin/src/integrationTest/groovy/org/myorg/http/DefaultHttpCallerIntegrationTest.groovy: 11: unable to resolve class DefaultHttpCaller
 @ line 11, column 38.
       @Subject HttpCaller httpCaller = new DefaultHttpCaller()
                                        ^

2 errors


> Task :compileIntegrationTestGroovy FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileIntegrationTestGroovy'.
> Compilation failed; see the compiler error output for details.

オリジナルはこの1行を次のように書いています。

    integrationTestImplementation(project)

projectを参照するって、どういう意味か?

わたしはここを sourceSets.main.output を参照するという風に限定的に書くことにした。同じ結果になるので、趣味の問題ですが。

Javaコードを網羅的に例示した

オリジナルはいくつかのJavaクラスのソースを示さず省略しています。

Classes that make the Custom Plugin
class name in the original

org.myorg.http.DefaultHttpCaller

presented

org.myorg.http.HttpCallException

missing

org.myorg.http.HttpCaller

missing

org.myorg.http.HttpResponse

presented

org.myorg.tasks.UrlVerify

presented

org.myorg.UrlVerifierException

missing

org.myorg.UrlVerifierPlugin

presented

オリジナルが省略したclassもあわせ、すべてのコードをサンプルに含めました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?