はじめに
カスタムなGradleプラグインを開発するにあたってテストをしたい。どういうコードを書けば自動化テストができるか?その方法を説明します。ちゃんと動くサンプルコード一式を提供します。
Gradle本家プロジェクトによるこの記事に基づいています。
使い方
前提していること
-
あなたの環境にJava8ないしそれ以降のJava環境がインストール済みであること
-
macOS v12.4でGradle v7.4.2を使ってこの記事をテストしました。WindowsやLinuxでも問題なく動くはずですが、わたしは試していません。
-
あなたがJavaプログラミングとGradleの基本を理解していることを前提します。
$ ./gradlw test
というコマンドが何をしているかというレベルの説明は省きます。
サンプルコードをどうやって手に入れるか
あなたがGitHubアカウントを持っているならば、このGitHubレポジトリのトップ the top page を開き、 をクリックしましょう。あなたのGitHubアカウントの中に新しいレポジトリとして本レポジトリの複製を作ることができます。
あなたがGitHubアカウントを持っていないならば、 Releasesページ を開き、最新の"Source code" のzipをダウンロードしてください。
自動化テストをどうやって実行するか
サンプルとして提供された自動化テストを走らせるにはコマンドラインで下記のように操作します。
$ 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
のための自動化テストです.
もうひとつ、テストのやり方の例があります。
$ 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-plugin
と include-plugin-build
)あって、各々が独立したGradleプロジェクトになっています。.
$ 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" と言うメッセージを標準出力に表示します。
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
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
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
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
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
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つあります。すなわち
-
src/main/
-
src/test/
-
src/integrationTest/
-
src/functionalTest/
これらサブディレクトリがGradleのSource Setに対応します。
$ 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
プラグインを使っています。
url-verifier-plugin/build.gradle
plugins {
id 'groovy'
id 'java-gradle-plugin'
groovy
プラグインを適用することにより、url-verifier-plugin
プロジェクトのなかに2つの source sets が自動的につくられます。すなわち main
と test
です。
main
ソースセットは url-verifier-plugin/src/main/
ディレクトリに格納されたソースコードに対応します。そこにはカスタムプラグインのソースがあります。
test
ソースセットは url-verifier-plugin/src/test/
ディレクトリに格納されたソースコードに対応します。そこにはユニットテストのソースがあります。
あと2つ、ソースセットを明示的に追加しました。すなわち integrationTest
と functionalTest
です。どうやって追加したか、次のコードを参照してください。
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行だけ設定を書く必要があります。
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に関する設定を記述しました。
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(…)
関する説明があります。
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
クラスに対するユニット・テストのコードは下記の通りです。
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 と呼び、ユニット・テストから区別することにします。
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/
- カスタムプラグインが完了したらプラグインの出力をテストが取り出して検証します。
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
を呼び出しています。
$ 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つあります。
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
に対して具体的な値を与えています。
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
ファイルは includeBuild
、dependencySubstitution
、 substitute
、 module
などの呪文を使っています。わたしは或る解説記事の一部をコピペして調節しました。このサンプルは実行するとちゃんと動きます。しかしわたしは呪文の意味がまだわかっていません。
別のやり方
url-verifier-plugin
プロジェクトが作ったカスタム・プラグインを`include-plugin-build` プロジェクトが実行できるように構成する方法がもう一つあります。org.myorg.url-verifier
を含むJARファイルを作って、それをMavenレポジトリにpublishする。publishされたJARファイルを include-plugin-build
プロジェクトが参照する、と言うやり方です。maven-publish
プラグインを使ってJARを作り mavenLocalレポジトリに publishしましょう。
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です。
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/'
}
include-plugin-build/settings.gradle
/* I do not use includeBuild */
このやり方はちゃんと動きます。しかしこのやり方には良くないところがある。2つ問題があります。
-
プラグインのコードを変更した後テストするたびに
publishToMavenLocal
タスクを繰り返し実行しなければならないのが面倒だ。 -
プラグインのバージョン番号(
1.2
)が2箇所に書いてある。url-verifier-plugin/build.gradle
ファイルのなかに書いてあるのは当然だが、include-plugin-build/build.gradle
ファイルにも書いてあるのがまずい。バージョンを変更しようとする時、片方のファイルだけ修正してもう片方を忘れるリスクがある。
オリジナルをどう手直ししたか
このレポジトリが示すサンプルコードはGradleプロジェクトが公開している下記の記事に基づいています。
この記事のことを指して「オリジナル」と呼ぶことにします。わたしが組み立てたサンプルコードはオリジナルと違うところがいくつかあります。どこを手直ししたのか、下記に列挙します。
Composite projectsの組み立て方
プラグイン利用者側プロジェクトをどうやってプラグイン開発プロジェクトと関連づけるかという問題があります。
オリジナル記事は次のようなコードを示しています。
include-plugin-build/build.gradle
plugins {
id 'org.myorg.url-verifier'
}
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)
...
わたしは次のように手直ししました。
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/'
}
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ソースセットに依存していることの表明
下記のコードを参照のこと。
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クラスのソースを示さず省略しています。
class name | in the original |
---|---|
presented |
|
missing |
|
missing |
|
presented |
|
presented |
|
missing |
|
presented |
オリジナルが省略したclassもあわせ、すべてのコードをサンプルに含めました。