Gradleのプラグインを正しくテストする

どういうわけか、Gradleのプラグインの開発に関するレポートの1つを準備すると、タスクが発生しました-スキルをテストする方法。 テストがなければ、一般的には生きがいがあります。コードが実際に別のプロセスで実行される場合、さらにデバッグが必要なため、すばやく実行したい場合や、考えられるすべてのケースをテストするために100万例を書きたくない場合があります。 catの下で、私たちが試みたいくつかのテスト方法の比較。







実験ウサギ



実験ウサギは、 JPoint 2016カンファレンスのためにtolkkvで準備したプロジェクトになります。 要するに、さまざまなプロジェクトからドキュメントを収集し、相互参照リンクを含む通常のhtmlドキュメントを生成するプラグインを作成しました。 しかし、それはプラグイン自体の書き方ではなく(楽しくて刺激的でしたが)、書いたものをどのようにテストするかではありません。 私は告白しますが、私たちが例を通して統合をテストしたプロジェクトのほぼ全体です。 そしてある時点で、彼らは別のテスト方法について考える価値があることに気づきました。 だから、私たちの候補者:









タスクはどこでも同じです。 ドキュメントプラグインが接続されていること、および正常に実行できるタスクがあることを確認してください。 追われた。







Gradleテストキット



現在、それはインキュベーション段階にあり、それをやろうとしたときに非常に顕著でした。 ドキュメンテーションから例を取り上げ、それを私たちの現実に単純に適用すると(以下の例を参照)、何も機能しません。 何をしたかを考えてみましょう。







@Slf4j class TestSpecification extends Specification { @Rule final TemporaryFolder testProjectDir = new TemporaryFolder() def buildFile def setup() { buildFile = testProjectDir.newFile('build.gradle') } def "execution of documentation distribution task is up to date"() { given: buildFile << """ buildscript { repositories { jcenter() } dependencies { classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.3' } } apply plugin: 'org.asciidoctor.convert' apply plugin: 'ru.jpoint.documentation' docs { debug = true } dependencies { asciidoctor 'org.asciidoctor:asciidoctorj:1.5.4' docs 'org.slf4j:slf4j-api:1.7.2' } """ when: def result = GradleRunner.create() .withProjectDir(testProjectDir.root) .withArguments('documentationDistZip') .build() then: result.task(":documentationDistZip").outcome == TaskOutcome.UP_TO_DATE } }
      
      





JUnitも使用できますが、Spockを使用します。 このプロジェクトは、 testProjectDir



で定義された一時フォルダーに置かれ、実行されます。 セットアップ方法では、新しいプロジェクトビルドファイルを作成します。 与えられたもので、このファイルのコンテンツを定義し、それに必要なプラグインと依存関係を接続しました。 whenセクションでは、新しいGradleRunner



クラスを使用して、以前に定義したディレクトリをプロジェクトに渡し、プラグインからタスクを実行することを伝えます。 その後のセクションでは、タスクがあることを確認しますが、ドキュメントを定義していないため、実行する必要はありません。







そのため、ここでテストを実行すると、テストフレームワークが接続したプラグイン( ru.jpoint.documentation



認識していないことがわかります。 なぜこれが起こっているのですか? 現在、 GradleRunner



は内部のプラグインのクラスパスを渡しません。 そして、これはテストで私たちを大きく制限します。 ドキュメントを調べて、必要なリソースを転送できるwithPluginClasspath



メソッドがあることを確認します。これらのメソッドは、テストプロセス中に取得されます。 それを形成する方法を理解することは残っています。







これが明白だと思うなら、もう一度考えてみてください。 この問題を解決するには、 build



ディレクトリに一連のリソースを含むテキストファイルを別のタスクで作成する必要があります(必須のアプローチについてはGradleに感謝します)。 私たちは書きます:







 task createClasspathManifest { def outputDir = sourceSets.test.output.resourcesDir inputs.files sourceSets.main.runtimeClasspath outputs.dir outputDir doLast { outputDir.mkdirs() file("$outputDir/plugin-classpath.txt").text = sourceSets.main.runtimeClasspath.join("\n") } }
      
      





まず、ファイルを受け取ります。 テストに進み、 セットアップで次のコード追加します。読みやすいです。







  def pluginClasspathResource = getClass().classLoader.findResource("plugin-classpath.txt") if (pluginClasspathResource == null) { throw new IllegalStateException("Did not find plugin classpath resource, run `testClasses` build task.") } pluginClasspath = pluginClasspathResource.readLines() .collect { new File(it) }
      
      





ここで、 classpath



GradleRunner



ます。 実行しても、何も機能しません。 フォーラムにアクセスすると、Gradle 2.8+でのみ機能することがわかります。 2.12があり、悲しいことを確認します。 どうする Gradle 2.7以前の場合は、指示どおりに実行してみましょう。 私たち自身が別のclasspath



を作成し、 buildscript



に直接追加しbuildscript









 def classpathString = pluginClasspath .collect { it.absolutePath.replace('\\', '\\\\') } .collect { "'$it'" } .join(", ")
      
      





 dependencies { classpath files($classpathString) ... }
      
      





起動-動作します。 これらがすべての問題ではありません。 あなたは壮大な貿易を読むことができ、それは完全に悲しくなるでしょう。







2.13更新:実験を行ったとき、新しいバージョンはまだリリースされていません。 リソースをプルアップする際の問題が(最終的に)修正され、コードはより適切で高貴になりました。 これを行うには、プラグインを少し異なる方法で接続する必要があります。







 plugins { id 'ru.jpoint.documentation' }
      
      





空のクラスパスでGradleRunner



を実行します:







 def result = GradleRunner.create() .withProjectDir(testProjectDir.root) .withArguments('documentationDistZip') .withPluginClasspath() .build()
      
      





残っているのは、Ideaがコンテキストメニューからこのテストを実行できないという悔しさだけです。必要なリソースを正しく置き換える方法がわからないためです。 ./gradlew



を通じて、すべてがうまく機能します。







d10xaからの修正 :「Gradle Test Runner」(設定->ビルド->ビルドツール-> Gradle->ランナー)を選択する必要がある設定で、既存の構成を削除し、テストを再度実行します。







結論:方向は正しいが、時には痛い。







星雲テスト



2番目の候補者は、はるかに良くなりました。 必要なことは、プラグインを依存関係に接続することだけです。







 functionalTestCompile 'com.netflix.nebula:nebula-test:4.0.0'
      
      





次に、仕様では、前の例と同様にbuild.gradle



ファイルを作成できます。







 def setup() { buildFile << """ buildscript { repositories { jcenter() } dependencies { classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.3' } } apply plugin: 'org.asciidoctor.convert' apply plugin: info.developerblog.documentation.plugin.DocumentationPlugin docs { debug = true } dependencies { asciidoctor 'org.asciidoctor:asciidoctorj:1.5.4' docs 'org.slf4j:slf4j-api:1.7.2' } """ }
      
      





しかし、テスト自体は簡単で理解しやすく、最も重要なことに見えます-スクワットなしで実行されます







 def "execution of documentation distribution task is success"() { when: createFile("/src/docs/asciidoc/documentation.adoc") ExecutionResult executionResult = runTasksSuccessfully('documentationDistZip') then: executionResult.wasExecuted('documentationDistZip') executionResult.getSuccess() }
      
      





この例では、ドキュメントを含むファイルも作成したため、タスクの実行結果はSUCCESS



ます。







結論:すべてが非常にクールです。 使用が推奨されます。







単体テスト



わかりました、私達が前にしたすべてはそのような統合テストすべてでした。 単体テストのメカニズムを通して何ができるかを見てみましょう。







まず、コードを使用してプロジェクトを構成します。







 def setup() { project = new ProjectBuilder().build() project.buildscript.repositories { jcenter() } project.buildscript.dependencies { classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.3' } project.plugins.apply('org.asciidoctor.convert') project.plugins.apply(DocumentationPlugin.class) project.dependencies { asciidoctor 'org.asciidoctor:asciidoctorj:1.5.4' docs 'org.slf4j:slf4j-api:1.7.2' } }
      
      





ご覧のとおり、これは以前に書いたものと実質的に違いClosure



ありません。 Closure



だけClosure



もう少し長く書かれています。







これで、プラグインからのタスクが構成済みプロジェクトに実際に表示されたことをテストできます(一般に構成は成功しました)。







 def "execution of documentation distribution task is success"() { when: project then: project.getTasksByName('documentationDistZip', true).size() == 1 }
      
      





しかし、これ以上テストすることはできません。 つまり、この方法では、タスクが想定どおりに機能することを理解できず、ドキュメントが実際に形成されるということです。







結論:プロジェクトの構成を確認するために使用できます。 これは、実際の実行によるテストよりも高速です。 しかし、私たちの可能性は非常に限られています。







まとめ



プラグインのNebula Test



にはNebula Test



を使用することをお勧めします。 プロジェクトの構成時に論理が緩い場合は、単体テストに目を向けることが理にかなっています。 まあ、私たちは完成したGradle Test Kit



待っています。







テストとプラグインを使用してプロジェクトにリンクします: https : //github.com/aatarasoff/documentation-plugin-demo








All Articles