plugin-under-test-metadata.properties 不是由 Gradle TestKit 在 IDEA 中进行 运行 测试时创建的
plugin-under-test-metadata.properties not created by Gradle TestKit when running tests in IDEA
我正在使用 Gradle 3.3 并尝试使用 JUnit 和 Gradle TestKit 测试自定义插件。在插件的 build.gradle
我有
version '0.1'
apply plugin: 'groovy'
apply plugin: 'java-gradle-plugin'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile project(':codegen-core')
compile localGroovy()
testCompile 'junit:junit:4.12'
}
考试是
package com.huawei.odmf.codegen.gradle
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import static org.junit.Assert.*
class TestOdmfCodegenPlugin {
@Rule
public final TemporaryFolder testProjectDir = new TemporaryFolder()
private File buildFile
private File assetsDir
@Before
void setUp() {
buildFile = testProjectDir.newFile("build.gradle")
assetsDir = testProjectDir.newFolder("src", "main", "assets")
}
@Test
void testPlugin() {
buildFile << """
plugins {
id 'com.huawei.odmf'
}
apply plugin: 'com.android.application'
odmf {
modelFile 'odmf.xml'
}
"""
BuildResult result = GradleRunner.create().
withProjectDir(testProjectDir.root).
withArguments(OdmfCodegenPlugin.taskName).
withPluginClasspath().
build()
// assertions
}
}
在src/main/resources/META-INF/gradle-plugins/com.huawei.odmf.properties
下我有
implementation-class=com.huawei.odmf.codegen.gradle.OdmfCodegenPlugin
根据 https://docs.gradle.org/current/userguide/test_kit.html#sub:test-kit-automatic-classpath-injection 和 automaticClasspathInjectionQuickstart
示例,这似乎是所有要求。
但是,此测试在 withPluginClasspath()
处失败(编辑:在 IDEA 中 运行 时;它从命令行运行),堆栈跟踪如下(据我了解,plugin-under-test-metadata.properties
是应该由 java-gradle-plugin
自动创建):
org.gradle.testkit.runner.InvalidPluginMetadataException: Test runtime classpath does not contain plugin metadata file 'plugin-under-test-metadata.properties'
at org.gradle.testkit.runner.internal.PluginUnderTestMetadataReading.readImplementationClasspath(PluginUnderTestMetadataReading.java:44)
at org.gradle.testkit.runner.internal.PluginUnderTestMetadataReading.readImplementationClasspath(PluginUnderTestMetadataReading.java:37)
at org.gradle.testkit.runner.internal.DefaultGradleRunner.withPluginClasspath(DefaultGradleRunner.java:146)
at org.gradle.testkit.runner.internal.DefaultGradleRunner$withPluginClasspath[=16=].call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
at com.huawei.odmf.codegen.gradle.TestOdmfCodegenPlugin.testPlugin(TestOdmfCodegenPlugin.groovy:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.rules.ExternalResource.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=16=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
我错过了什么?
确定问题仅出在 IDEA 中后,我找到了 https://plugins.gradle.org/plugin/com.palantir.idea-test-fix 并添加了
plugins {
id "com.palantir.idea-test-fix" version "0.1.0"
}
到插件子项目的 build.gradle
开头。它解决了问题。
在this post (Russian),我找到了另一个解决方案:在Settings-> Build-> Build Tools->Gradle->Runner
,select Gradle Test Runner
而不是Platform Test Runner
,然后删除测试的run/debug之前的配置运行再说一遍。
plugins {
id "org.jetbrains.gradle.plugin.idea-ext" version "0.4.2"
}
task fixIdeaPluginClasspath {
doFirst {
configure(tasks.pluginUnderTestMetadata) {
def ideaClassesPath = project.buildDir.toPath().resolveSibling("out").resolve("production")
def newClasspath = pluginClasspath as List
newClasspath.add(0, ideaClassesPath)
pluginClasspath.setFrom(newClasspath)
}
}
}
pluginUnderTestMetadata.mustRunAfter(fixIdeaPluginClasspath)
idea.project.settings {
taskTriggers {
beforeBuild fixIdeaPluginClasspath, pluginUnderTestMetadata
}
}
这适用于 IDEA 2019.1(也可能适用于早期版本)。
这利用 JetBrains' own gradle plugin for configuring IDEA settings 在每次构建之前执行 pluginUnderTestMetadata
和自定义 fixIdeaPluginClasspath
(后者只会从 IDEA 中 运行,而不是 运行宁本土gradle).
第一个任务 -- pluginUnderTestMetadata
-- 确保创建属性文件,并由本机执行 Gradle。
第二个任务——fixIdeaPluginClasspath
——修复了 IDEA 如何执行测试的另一个错误:pluginUnderTestMetadata
生成的类路径将只包含对 "$projectDir/build"
目录的引用,该目录是不是 IDEA 输出其编译的 类 的地方;因此,您不会看到您在 IDEA 编译的插件代码中所做的更改,而只会看到原生 gradle 编译的那些。然后它所做的是将 IDEA 类 目录添加到类路径中。起初我也尝试删除 "$projectDir/build"
引用,但是 gradle 然后不喜欢它抱怨插件命名空间问题(对我来说太巫毒了)。
感谢 @krzychu 指出 pluginUnderTestMetadata
(在之前回答的评论中)。
在 Gradle 4 中,我尝试使用 gradleTestKit()
并遇到此错误。
- 添加以下插件修复它。
plugins {
id 'java-gradle-plugin'
}
这可能是由于 pluginUnderTestMetadata
未在测试前执行。这就是生成元数据的原因,您的执行会抱怨这些元数据。
解决此问题的一种方法是将该任务添加为测试的要求:
tasks.withType<Test> {
dependsOn("pluginUnderTestMetadata")
}
一些测试执行者在执行测试之前可能没有捕捉到这一点。作为一种解决方法,您可以在编译测试时依赖它 类:
tasks.named("testClasses") {
dependsOn("pluginUnderTestMetadata")
}
对于 build.gradle.kts
(kotlin) 你可以使用:
val createClasspathManifest = tasks.create("createClasspathManifest") {
val outputDir = file("$buildDir/$name")
inputs.files(sourceSets.main.get().runtimeClasspath)
inputs.files(project(":core").sourceSets.main.get().runtimeClasspath)
outputs.dir(outputDir)
doLast {
outputDir.mkdirs()
val joined = sourceSets.main.get().runtimeClasspath.joinToString("\n") +
project(":core").sourceSets.main.get().runtimeClasspath.joinToString("\n")
file("$outputDir/plugin-classpath.txt").writeText(joined)
}
}
dependencies {
testApi(files(createClasspathManifest))
}
我正在使用 Gradle 3.3 并尝试使用 JUnit 和 Gradle TestKit 测试自定义插件。在插件的 build.gradle
我有
version '0.1'
apply plugin: 'groovy'
apply plugin: 'java-gradle-plugin'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile project(':codegen-core')
compile localGroovy()
testCompile 'junit:junit:4.12'
}
考试是
package com.huawei.odmf.codegen.gradle
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import static org.junit.Assert.*
class TestOdmfCodegenPlugin {
@Rule
public final TemporaryFolder testProjectDir = new TemporaryFolder()
private File buildFile
private File assetsDir
@Before
void setUp() {
buildFile = testProjectDir.newFile("build.gradle")
assetsDir = testProjectDir.newFolder("src", "main", "assets")
}
@Test
void testPlugin() {
buildFile << """
plugins {
id 'com.huawei.odmf'
}
apply plugin: 'com.android.application'
odmf {
modelFile 'odmf.xml'
}
"""
BuildResult result = GradleRunner.create().
withProjectDir(testProjectDir.root).
withArguments(OdmfCodegenPlugin.taskName).
withPluginClasspath().
build()
// assertions
}
}
在src/main/resources/META-INF/gradle-plugins/com.huawei.odmf.properties
下我有
implementation-class=com.huawei.odmf.codegen.gradle.OdmfCodegenPlugin
根据 https://docs.gradle.org/current/userguide/test_kit.html#sub:test-kit-automatic-classpath-injection 和 automaticClasspathInjectionQuickstart
示例,这似乎是所有要求。
但是,此测试在 withPluginClasspath()
处失败(编辑:在 IDEA 中 运行 时;它从命令行运行),堆栈跟踪如下(据我了解,plugin-under-test-metadata.properties
是应该由 java-gradle-plugin
自动创建):
org.gradle.testkit.runner.InvalidPluginMetadataException: Test runtime classpath does not contain plugin metadata file 'plugin-under-test-metadata.properties'
at org.gradle.testkit.runner.internal.PluginUnderTestMetadataReading.readImplementationClasspath(PluginUnderTestMetadataReading.java:44)
at org.gradle.testkit.runner.internal.PluginUnderTestMetadataReading.readImplementationClasspath(PluginUnderTestMetadataReading.java:37)
at org.gradle.testkit.runner.internal.DefaultGradleRunner.withPluginClasspath(DefaultGradleRunner.java:146)
at org.gradle.testkit.runner.internal.DefaultGradleRunner$withPluginClasspath[=16=].call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
at com.huawei.odmf.codegen.gradle.TestOdmfCodegenPlugin.testPlugin(TestOdmfCodegenPlugin.groovy:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.rules.ExternalResource.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=16=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
我错过了什么?
确定问题仅出在 IDEA 中后,我找到了 https://plugins.gradle.org/plugin/com.palantir.idea-test-fix 并添加了
plugins {
id "com.palantir.idea-test-fix" version "0.1.0"
}
到插件子项目的 build.gradle
开头。它解决了问题。
在this post (Russian),我找到了另一个解决方案:在Settings-> Build-> Build Tools->Gradle->Runner
,select Gradle Test Runner
而不是Platform Test Runner
,然后删除测试的run/debug之前的配置运行再说一遍。
plugins {
id "org.jetbrains.gradle.plugin.idea-ext" version "0.4.2"
}
task fixIdeaPluginClasspath {
doFirst {
configure(tasks.pluginUnderTestMetadata) {
def ideaClassesPath = project.buildDir.toPath().resolveSibling("out").resolve("production")
def newClasspath = pluginClasspath as List
newClasspath.add(0, ideaClassesPath)
pluginClasspath.setFrom(newClasspath)
}
}
}
pluginUnderTestMetadata.mustRunAfter(fixIdeaPluginClasspath)
idea.project.settings {
taskTriggers {
beforeBuild fixIdeaPluginClasspath, pluginUnderTestMetadata
}
}
这适用于 IDEA 2019.1(也可能适用于早期版本)。
这利用 JetBrains' own gradle plugin for configuring IDEA settings 在每次构建之前执行 pluginUnderTestMetadata
和自定义 fixIdeaPluginClasspath
(后者只会从 IDEA 中 运行,而不是 运行宁本土gradle).
第一个任务 -- pluginUnderTestMetadata
-- 确保创建属性文件,并由本机执行 Gradle。
第二个任务——fixIdeaPluginClasspath
——修复了 IDEA 如何执行测试的另一个错误:pluginUnderTestMetadata
生成的类路径将只包含对 "$projectDir/build"
目录的引用,该目录是不是 IDEA 输出其编译的 类 的地方;因此,您不会看到您在 IDEA 编译的插件代码中所做的更改,而只会看到原生 gradle 编译的那些。然后它所做的是将 IDEA 类 目录添加到类路径中。起初我也尝试删除 "$projectDir/build"
引用,但是 gradle 然后不喜欢它抱怨插件命名空间问题(对我来说太巫毒了)。
感谢 @krzychu 指出 pluginUnderTestMetadata
(在之前回答的评论中)。
在 Gradle 4 中,我尝试使用 gradleTestKit()
并遇到此错误。
- 添加以下插件修复它。
plugins {
id 'java-gradle-plugin'
}
这可能是由于 pluginUnderTestMetadata
未在测试前执行。这就是生成元数据的原因,您的执行会抱怨这些元数据。
解决此问题的一种方法是将该任务添加为测试的要求:
tasks.withType<Test> {
dependsOn("pluginUnderTestMetadata")
}
一些测试执行者在执行测试之前可能没有捕捉到这一点。作为一种解决方法,您可以在编译测试时依赖它 类:
tasks.named("testClasses") {
dependsOn("pluginUnderTestMetadata")
}
对于 build.gradle.kts
(kotlin) 你可以使用:
val createClasspathManifest = tasks.create("createClasspathManifest") {
val outputDir = file("$buildDir/$name")
inputs.files(sourceSets.main.get().runtimeClasspath)
inputs.files(project(":core").sourceSets.main.get().runtimeClasspath)
outputs.dir(outputDir)
doLast {
outputDir.mkdirs()
val joined = sourceSets.main.get().runtimeClasspath.joinToString("\n") +
project(":core").sourceSets.main.get().runtimeClasspath.joinToString("\n")
file("$outputDir/plugin-classpath.txt").writeText(joined)
}
}
dependencies {
testApi(files(createClasspathManifest))
}