使用Cucumber-Java8时总是收到“常量池索引处的错误类型”异常

9

我正在尝试为Cucumber的Java8方言设置示例项目。我的问题是,我无法运行它。我总是得到以下一系列异常:

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.068 sec <<< FAILURE! - in soy.wimmer.CucumberIT
Feature: Cucumber with Java8  Time elapsed: 0.051 sec  <<< ERROR!
cucumber.runtime.CucumberException: Failed to instantiate class soy.wimmer.CucumberStepdefs
[…]
Caused by: java.lang.reflect.InvocationTargetException: null
[…]
Caused by: cucumber.runtime.CucumberException: java.lang.IllegalArgumentException: Wrong type at constant pool index
[…]
Caused by: java.lang.IllegalArgumentException: Wrong type at constant pool index
    at sun.reflect.ConstantPool.getMemberRefInfoAt0(Native Method)
    at sun.reflect.ConstantPool.getMemberRefInfoAt(ConstantPool.java:47)
    at cucumber.runtime.java8.ConstantPoolTypeIntrospector.getTypeString(ConstantPoolTypeIntrospector.java:37)
    at cucumber.runtime.java8.ConstantPoolTypeIntrospector.getGenericTypes(ConstantPoolTypeIntrospector.java:27)
    at cucumber.runtime.java.Java8StepDefinition.<init>(Java8StepDefinition.java:45)
    at cucumber.runtime.java.JavaBackend.addStepDefinition(JavaBackend.java:162)
    at cucumber.api.java8.En.Given(En.java:190)
    at soy.wimmer.CucumberStepdefs.<init>(CucumberStepdefs.java:8)
[…]

Results :

Tests in error: 
  Failed to instantiate class soy.wimmer.CucumberStepdefs

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0

我不知道为什么会出现这个错误,也不知道该如何修复它。

我把所有东西都打包在一个Maven项目中。布局如下:

./src/test/java/soy/wimmer/CucumberIT.java
./src/test/java/soy/wimmer/CucumberStepdefs.java
./src/test/resources/cucumber/cucumber-java8.feature
./pom.xml

我在pom.xml中包含的依赖项如下:

<dependencies>                                                               
    <dependency>                                                             
        <groupId>info.cukes</groupId>                                        
        <artifactId>cucumber-java8</artifactId>                              
        <version>1.2.3</version>                                             
        <scope>test</scope>                                                  
    </dependency>                                                            

    <dependency>                                                             
        <groupId>info.cukes</groupId>                                        
        <artifactId>cucumber-junit</artifactId>                              
        <version>1.2.3</version>                                             
        <scope>test</scope>                                                  
    </dependency>                                                            

    <dependency>                                                             
        <groupId>junit</groupId>                                             
        <artifactId>junit</artifactId>                                       
        <version>4.12</version>                                              
        <scope>test</scope>                                                  
    </dependency>                                                            
</dependencies>

此外pom.xml只加载编译器和failsafe插件。
CucumberIT.java的定义:
package soy.wimmer;                                                              

import cucumber.api.CucumberOptions;                                             
import cucumber.api.junit.Cucumber;                                              
import org.junit.runner.RunWith;                                                 

@RunWith(Cucumber.class)                                                         
@CucumberOptions(features = "classpath:cucumber")                                
public class CucumberIT {                                                        
}        

我的特性定义:

Feature: Cucumber with Java8                                                     
        As a developer                                                           
        I want to use Cucumber-java8                                             
        So that I have nicer step definitions                                    

        Scenario: Let's try it                                                   
                Given I have some dummy code                                     
                When I try to test it                                            
                Then it should work with cucumber-java8  

这是我的步骤定义:

package soy.wimmer;                                                              

import cucumber.api.PendingException;                                            
import cucumber.api.java8.En;                                                    

public class CucumberStepdefs implements En {                                    
    public CucumberStepdefs() {                                                  
        Given("^I have some dummy code$", () -> {                                
            // Write code here that turns the phrase above into concrete actions 
            throw new PendingException();                                        
        });                                                                      

        When("^I try to test it$", () -> {                                       
            // Write code here that turns the phrase above into concrete actions 
            throw new PendingException();                                        
        });                                                                      

        Then("^it should work with cucumber-java(\\d+)$", (Integer arg1) -> {    
            // Write code here that turns the phrase above into concrete actions 
            throw new PendingException();                                        
        });                                                                      
    }                                                                            
}

有没有想法,我在这里做错了什么?

正如链接答案中所说,问题并不在编译器上。问题在于有一个运行时工具试图处理已编译的类文件,也就是字节码。请查看抛出“IllegalArgumentException”的方法。 - Holger
这是一条重要信息。通过包含的堆栈跟踪,我们可以得出结论,这很可能是一个不同的问题。 - Holger
3
我们发现Cucumber正在侵入Java的私有类,即sun.reflect.ConstantPool,这是引起兼容性问题的一种方法,但情况变得更糟了,看看有问题的代码行。糟透了。怎么可能认为常量池的任何一个随意位置(大小-2)包含某个特定信息呢?那高度依赖编译器,即使使用相同的编译器也不能保证这些项目的任何特定顺序。 - Holger
好的,谢谢您的检查。所以也许我现在不应该尝试使用Cucumber的Java8方言,最好还是坚持使用通用的Java方言。 - Matthias Wimmer
我可以确认,这似乎是cucumber-java8的编译器依赖关系。通常我使用OpenJDK。我刚刚尝试使用Sun的JDK8编译/运行相同的测试,它立即起作用了。 - Matthias Wimmer
显示剩余3条评论
2个回答

10
问题是由于Cucumber的Java8方言使用了Oracle JDK8的实现细节所引起的。
我使用Debian打包的OpenJDK8,这导致常量池的组织方式不同。当我尝试使用Oracle JDK8时,一切都按预期工作。
如果您想自己尝试,请在github上发布完整的示例项目: https://github.com/mawis/cucumber-java8-test 我还在cucumber-jvm的问题跟踪器中报告了一个错误: https://github.com/cucumber/cucumber-jvm/issues/912 您可能会查看问题跟踪器,以查看问题是否将来已经得到解决。
目前,如果您想使用cucumber-java8,似乎必须使用Oracle的JDK实现。
(感谢Holger对该问题的评论,他解决了这个问题的名声。我只是想写这篇答案作为总结。)

1
如果我理解正确的话,只要我使用Oracle的JDK,我应该能看到这个工作。然而,我得到了与原帖作者完全相同的错误。我正在使用Java版本1.8.0_60,作为Oracle JDK的一部分下载。 - Jeff Nyman
5
似乎还取决于您正在使用的JDK版本。 Oracle的最近几个版本似乎效果不太好。 - Matthias Wimmer

7

只需使用最近发布的1.2.5版本即可。此版本修复了被采纳的答案中提到的错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接