【问题标题】:Can TestNG see my Spock (JUnit) test results?TestNG 可以看到我的 Spock (JUnit) 测试结果吗?
【发布时间】:2014-05-03 05:54:57
【问题描述】:

需要让 TestNG 运行我的 Spock 测试,因为 TestNG 在整个系统的其余部分都使用。
由于 TestNG 支持运行 JUnit 测试,我尝试了这个:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="suiteTestName" verbose="1" junit="true">
    <test name="myTestName">
        <classes>
            <class name="mypackage.artifact.SomeArtifactSpecification" />
        </classes>
    </test>
</suite>

所以这实际上完美地运行了 Groovy 'SomeArtifactSpecification' Spock 单元测试。我可以从测试中看到一些 I/O,但由于我是在 Eclipse 中运行的,所以我使用调试器来验证所有测试是否正确执行。我的类路径上有 TestNG-6.8.7 和 JUnit-4.10。问题是 TestNG 似乎并不知道它确实如此!这是最终输出:

===============================================
myTestName
Total tests run: 0, Failures: 0, Skips: 0
===============================================

有谁知道是否可以让 TestNG 识别这些测试?

其他细节 - 为赏金添加

在下面的其中一个 cmets 中,Peter 指出这取决于 TestNG 正在做什么。我尽可能地对此进行了调查。似乎 Junit 和 TestNG 都调用了 Spock 的 Sputnik 类第 63 行的“运行”方法。但是,当直接从 JUnit 调用时,从 JUnit4TestClassReference 调用 Sputnik。当从 TestNG 调用时,从 JUnitCore 调用 Sputnik。

所以问题仍然存在:如何让 TestNG 识别 Spock 的测试输出?如果我要长寿和繁荣,我真的需要知道!!!似乎答案可能是让 TestNG 与 JUnit4TestClassReference 一起运行,或者使用某种巧妙的包装器让 TestNG 做到这一点......

对于血淋淋的细节,我在下面发布了两个堆栈跟踪。第一个是TestNG运行,它不起作用,第二个是直接运行Spock而不使用TestNG。

TestNG 的第一个堆栈跟踪:

org.testng.remote.RemoteTestNG at localhost:54288   
Thread [main] (Suspended (breakpoint at line 65 in ArtifactManagerSpecification))   
    ArtifactManagerSpecification.$spock_feature_0_0() line: 65  
    NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
    NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57  
    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  
    Method.invoke(Object, Object...) line: 601  
    ReflectionUtil.invokeMethod(Object, Method, Object...) line: 138    
    ParameterizedSpecRunner(BaseSpecRunner).invokeRaw(Object, MethodInfo, Object...) line: 330  
    ParameterizedSpecRunner(BaseSpecRunner).invoke(Object, MethodInfo, Object...) line: 311 
    ParameterizedSpecRunner(BaseSpecRunner).invokeFeatureMethod() line: 285 
    ParameterizedSpecRunner(BaseSpecRunner).doRunIteration() line: 256  
    NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
    NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57  
    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  
    Method.invoke(Object, Object...) line: 601  
    ReflectionUtil.invokeMethod(Object, Method, Object...) line: 138    
    ParameterizedSpecRunner(BaseSpecRunner).invokeRaw(Object, MethodInfo, Object...) line: 330  
    ParameterizedSpecRunner(BaseSpecRunner).invoke(Object, MethodInfo, Object...) line: 311 
    ParameterizedSpecRunner(BaseSpecRunner).runIteration(Object[], int) line: 223   
    ParameterizedSpecRunner(BaseSpecRunner).initializeAndRunIteration(Object[], int) line: 214  
    ParameterizedSpecRunner(BaseSpecRunner).runSimpleFeature() line: 205    
    ParameterizedSpecRunner(BaseSpecRunner).doRunFeature() line: 199    
    NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
    NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57  
    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  
    Method.invoke(Object, Object...) line: 601  
    ReflectionUtil.invokeMethod(Object, Method, Object...) line: 138    
    ParameterizedSpecRunner(BaseSpecRunner).invokeRaw(Object, MethodInfo, Object...) line: 330  
    ParameterizedSpecRunner(BaseSpecRunner).invoke(Object, MethodInfo, Object...) line: 311 
    ParameterizedSpecRunner(BaseSpecRunner).runFeature() line: 175  
    ParameterizedSpecRunner(BaseSpecRunner).runFeatures() line: 152 
    ParameterizedSpecRunner(BaseSpecRunner).doRunSpec() line: 112   
    NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
    NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57  
    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  
    Method.invoke(Object, Object...) line: 601  
    ReflectionUtil.invokeMethod(Object, Method, Object...) line: 138    
    ParameterizedSpecRunner(BaseSpecRunner).invokeRaw(Object, MethodInfo, Object...) line: 330  
    ParameterizedSpecRunner(BaseSpecRunner).invoke(Object, MethodInfo, Object...) line: 311 
    ParameterizedSpecRunner(BaseSpecRunner).runSpec() line: 91  
    ParameterizedSpecRunner(BaseSpecRunner).run() line: 82  
    Sputnik.run(RunNotifier) line: 63   
    JUnitCore.run(Runner) line: 157 
    JUnitCore.run(Request) line: 136    
    JUnit4TestRunner.start(Class, String...) line: 81   
    JUnit4TestRunner.run(Class, String...) line: 69 
    TestRunner$1.run() line: 682    
    TestRunner.runWorkers(List<IWorker<ITestNGMethod>>, String, ListMultiMap<Integer,TestMethodWorker>) line: 1005  
    TestRunner.privateRunJUnit(XmlTest) line: 713   
    TestRunner.run() line: 614  
    SuiteRunner.runTest(TestRunner) line: 334   
    SuiteRunner.runSequentially() line: 329 
    SuiteRunner.privateRun() line: 291  
    SuiteRunner.run() line: 240 
    SuiteRunnerWorker.runSuite(SuiteRunnerMap, XmlSuite) line: 52   
    SuiteRunnerWorker.run() line: 86    
    RemoteTestNG(TestNG).runSuitesSequentially(XmlSuite, SuiteRunnerMap, int, String) line: 1224    
    RemoteTestNG(TestNG).runSuitesLocally() line: 1149  
    RemoteTestNG(TestNG).run() line: 1057   
    RemoteTestNG.run() line: 111    
    RemoteTestNG.initAndRun(String[], CommandLineArgs, RemoteArgs) line: 204    
    RemoteTestNG.main(String[]) line: 175   

直接运行 Spock 的第二个堆栈跟踪(有效)

Thread [main] (Suspended (breakpoint at line 65 in ArtifactManagerSpecification))   
ArtifactManagerSpecification.$spock_feature_0_0() line: 65  
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57  
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  
Method.invoke(Object, Object...) line: 601  
ReflectionUtil.invokeMethod(Object, Method, Object...) line: 138    
ParameterizedSpecRunner(BaseSpecRunner).invokeRaw(Object, MethodInfo, Object...) line: 330  
ParameterizedSpecRunner(BaseSpecRunner).invoke(Object, MethodInfo, Object...) line: 311 
ParameterizedSpecRunner(BaseSpecRunner).invokeFeatureMethod() line: 285 
ParameterizedSpecRunner(BaseSpecRunner).doRunIteration() line: 256  
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57  
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  
Method.invoke(Object, Object...) line: 601  
ReflectionUtil.invokeMethod(Object, Method, Object...) line: 138    
ParameterizedSpecRunner(BaseSpecRunner).invokeRaw(Object, MethodInfo, Object...) line: 330  
ParameterizedSpecRunner(BaseSpecRunner).invoke(Object, MethodInfo, Object...) line: 311 
ParameterizedSpecRunner(BaseSpecRunner).runIteration(Object[], int) line: 223   
ParameterizedSpecRunner(BaseSpecRunner).initializeAndRunIteration(Object[], int) line: 214  
ParameterizedSpecRunner(BaseSpecRunner).runSimpleFeature() line: 205    
ParameterizedSpecRunner(BaseSpecRunner).doRunFeature() line: 199    
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57  
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  
Method.invoke(Object, Object...) line: 601  
ReflectionUtil.invokeMethod(Object, Method, Object...) line: 138    
ParameterizedSpecRunner(BaseSpecRunner).invokeRaw(Object, MethodInfo, Object...) line: 330  
ParameterizedSpecRunner(BaseSpecRunner).invoke(Object, MethodInfo, Object...) line: 311 
ParameterizedSpecRunner(BaseSpecRunner).runFeature() line: 175  
ParameterizedSpecRunner(BaseSpecRunner).runFeatures() line: 152 
ParameterizedSpecRunner(BaseSpecRunner).doRunSpec() line: 112   
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57  
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  
Method.invoke(Object, Object...) line: 601  
ReflectionUtil.invokeMethod(Object, Method, Object...) line: 138    
ParameterizedSpecRunner(BaseSpecRunner).invokeRaw(Object, MethodInfo, Object...) line: 330  
ParameterizedSpecRunner(BaseSpecRunner).invoke(Object, MethodInfo, Object...) line: 311 
ParameterizedSpecRunner(BaseSpecRunner).runSpec() line: 91  
ParameterizedSpecRunner(BaseSpecRunner).run() line: 82  
Sputnik.run(RunNotifier) line: 63   
JUnit4TestClassReference(JUnit4TestReference).run(TestExecution) line: 50   
TestExecution.run(ITestReference[]) line: 38    
RemoteTestRunner.runTests(String[], String, TestExecution) line: 467    
RemoteTestRunner.runTests(TestExecution) line: 683  
RemoteTestRunner.run() line: 390    
RemoteTestRunner.main(String[]) line: 197   

【问题讨论】:

  • 据我所知,TestNG 只能运行 JUnit 3 测试,不能运行 JUnit 4 测试。在这种情况下,它将无法运行 Spock 规范。
  • 虽然我离专家很远(好吧,很远!),但几个月前他们显然已经增加了对 JUnit 4 的支持。我正在使用的版本中提供了这种支持。
  • 他们还必须添加对自定义 JUnit 运行器的支持 (@RunWith)。我在文档中没有看到任何关于此(或一般的 JUnit 4 支持)的信息,但我只是快速浏览了一下。
  • 我不太明白。这不就是 JUnit 尊重 spock.lang.Specification 中的 @RunWith 吗?无论如何,在上述情况下,如果我在 Sputnik 的构造函数中放置了一个断点(顺便说一句,伟大的名字!),它确实会立即到达那里。它也适用于 Sputnik 的“运行”方法......
  • 这完全取决于 TestNG 如何执行 JUnit 测试。

标签: unit-testing groovy junit testng spock


【解决方案1】:

我对此进行了进一步调查,至少找到了原因。

org.testng.junit.JUnit4TestMethod 中,Spock 测试名称无法正确解析。我在猜测,但我认为 Spock 使用一种名称修饰来支持它允许的漂亮文本方法名称。因此,即使下面的 TestNG 代码获得了像“这是我的测试”这样的方法名称,它也无法通过所示的方法解决这个问题。我相信真正的方法名称类似于:$spock_feature_0_0

private static Method getMethod(Description desc) {
    Class<?> c = desc.getTestClass();
    String method = desc.getMethodName();
    try {
        return c.getMethod(method);
    } catch (Throwable t) {
        Utils.log("JUnit4TestMethod", 2,
                "Method '" + method + "' not found in class '" + c.getName() + "': " + t.getMessage());
        return null;
    }
}

因此,这会在调用 c.getMethod(method) 时引发异常 - 它无法将 Spock 方法名称解析为类上的实际方法。

似乎真正“搞砸了情况”的是,上面的代码是由 Junit (org.junit.runner.notification.RunNotifier) 在这段代码中调用的:

private abstract class SafeNotifier {
    void run() {
        synchronized (fListeners) {
            for (Iterator<RunListener> all= fListeners.iterator(); all.hasNext();)
                try {
                    notifyListener(all.next());
                } catch (Exception e) {
                    all.remove(); // Remove the offending listener first to avoid an infinite loop
                    fireTestFailure(new Failure(Description.TEST_MECHANISM, e));
                }
        }
    }

这段代码最好不要悄悄删除监听器,而是记录它...

【讨论】:

  • 是的,这很可能是问题的根源。
  • 为了证明您的理论,将您所有的 Spock 测试名称重命名为传统的 Java 方法名称还不够吗?
猜你喜欢
  • 1970-01-01
  • 2017-05-29
  • 1970-01-01
  • 1970-01-01
  • 2020-01-07
  • 1970-01-01
  • 1970-01-01
  • 2011-02-04
  • 1970-01-01
相关资源
最近更新 更多