plugin-under-test-metadata.properties在IDEA中运行测试时不是由Gradle TestKit创建的

plugin-under-test-metadata.properties在IDEA中运行测试时不是由Gradle TestKit创建的,gradle,gradle-plugin,Gradle,Gradle Plugin,我正在使用Gradle3.3,并试图用JUnit和GradleTestKit测试一个自定义插件。在plugin的build.gradle中 测试是 package com.huawei.odmf.codegen.gradle import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome

我正在使用Gradle3.3,并试图用JUnit和GradleTestKit测试一个自定义插件。在plugin的build.gradle中

测试是

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
    }
}
这似乎是automaticClasspathInjectionQuickstart示例所需的全部内容

但是,该测试在withPluginClasspath编辑时失败:在IDEA中运行时;据我所知,它从命令行开始使用以下堆栈跟踪,plugin-under-test-metadata.properties应该由java gradle插件自动创建:

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$0.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$1.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$1.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$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.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中出现后,我发现并添加了

plugins {
  id "com.palantir.idea-test-fix" version "0.1.0"
}
转到插件子项目的build.gradle的开头。它解决了这个问题

在中,我找到了另一个解决方案:在设置->构建->构建工具->渐变->运行程序中,选择渐变测试运行程序而不是平台测试运行程序,然后在再次运行之前删除测试的运行/调试配置

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,也可能适用于早期版本

这利用了在每次构建之前执行pluginUnderTestMetadata和自定义fixIdeaPluginClasspath,后者将仅从IDEA内部运行,而不是在运行本机gradle时

第一个任务——pluginUnderTestMetadata——确保创建属性文件,并由本机Gradle执行

第二个任务——fixidapluginclasspath——修复了IDEA执行测试的另一个bug:由pluginUnderTestMetadata生成的类路径将只包含对$projectDir/build目录的引用,IDEA不会在该目录中输出其编译的类;因此,您不会看到IDEA编译的插件代码中所做的更改,而只会看到native gradle编译的插件代码。然后,它所做的是将IDEA classes目录前置到classpath。起初,我还尝试删除$projectDir/build引用,但是gradle不喜欢它抱怨插件名称空间问题,这对我来说太巫毒了


感谢您在前面的回答中指出pluginUnderTestMetadata。

在Gradle4中,我试图使用gradleTestKit,但出现了此错误

添加下面的插件修复了它。
这可能是由于测试之前未执行pluginUnderTestMetadata造成的。这就是生成元数据的原因,您的执行正在抱怨元数据

解决此问题的一种方法是将该任务添加为测试要求:

tasks.withType{ dependsOnpluginUnderTestMetadata } 一些测试执行者在执行测试之前可能无法捕捉到这一点。作为一种解决方法,您可以在编译测试类时依赖于此:

tasks.namedTestClass{ dependsOnpluginUnderTestMetadata }
据我所知,您不需要显式调用pluginclasspath。不要显式地调用它。如果有效,请告诉我,然后我给出一个答案。@Vampire不幸的是,它没有:插件[id:'com.huawei.odmf']在以下任何一个中都没有找到sources@Vampire它在命令行中也不起作用,但事实证明使用pluginclasspath调用的版本确实起作用。啊,好吧,很有趣。不幸的是,该插件的repo被删除或私有。是的,这是不幸的。我也无法切换到4.0并检查问题是否仍然存在,因此我不知道是否应该向Gradle报告错误。IntelliJ 2017.2也存在同样的问题。我无法让com.palantir.idea-test-fix正常工作,但是改变为gradle测试运行者的技巧非常有效!顺便说一句,这个问题发生在我尝试使用这里记录的vanilla gradle插件示例时:IDEA 2017.2.5和gradle 4.3仍然存在问题。更改跑步者并删除跑步配置修复了它,谢谢!所描述的解决方案并没有解决我的问题,但运行./gradlew pluginUnderTestMetadata解决了问题。在IDEA 2020.2中,唯一的解决方法是进入设置>构建>渐变>您的项目>使用并选择渐变默认运行测试。我还为他们打开了一个错误:同意,我在没有上述行的情况下使用渐变测试工具包时遇到了相同的错误,当我搜索谷歌时,我找到了你的问题。我知道StackOverflow不喜欢不相关的答案,所以我们真的无法回答次要问题:这确实是正确的答案:
plugins {
  id "com.palantir.idea-test-fix" version "0.1.0"
}
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
    }
}
plugins {
    id 'java-gradle-plugin'
}