繁体   English   中英

在 Springboot 中运行 Cucumber,在可执行文件 JAR 中运行 Maven

[英]Running Cucumber in Springboot with Maven in executable JAR

各位工程师好!

我在尝试创建 FAT jar 以执行 Cucumber 测试时遇到问题。 最初,我按照指南从Baeldung设置测试。 在 Maven 测试阶段执行时,测试工作正常。 当使用参数运行 mvn exec:java 命令时,它也按预期工作。

但是,当我创建了一个 FAT jar 并尝试执行测试时,我遇到了错误

java.util.concurrent.ExecutionException: io.cucumber.core.backend.CucumberBackendException: Please annotate a glue class with some context configuration.

For example:

   @CucumberContextConfiguration
   @SpringBootTest(classes = TestConfig.class)
   public class CucumberSpringConfiguration { }
Or:

   @CucumberContextConfiguration
   @ContextConfiguration( ... )

这是我的项目的解释,基本上和Baeldung的测试项目几乎一模一样。

项目结构

RunCucumberTest.java

package com.ing.testsuite;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Configuration;
import io.cucumber.*;


@RunWith(Cucumber.class)
@CucumberOptions(features="src/test/resources", glue="com.ing.testsuite", plugin = {"pretty","html:target/cucumber.html"})
class RunCucumberTest {

    public static void main(String[] args) throws Throwable {
        String[] arguments = {"classpath:dummy.feature", "classpath:com.ing.testsuite"};
        io.cucumber.core.cli.Main.main(arguments);
    }
}

CucumberSpringConfiguration.java

package com.ing.testsuite;

import io.cucumber.spring.CucumberContextConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;

@CucumberContextConfiguration
@SpringBootTest(classes = RunCucumberTest.class)
public class CucumberSpringConfiguration{
}

步骤定义.java

package com.ing.testsuite;

import static org.junit.jupiter.api.Assertions.assertEquals;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.When;
import io.cucumber.java.en.Then;

public class StepDefinitions extends CucumberSpringConfiguration{

    private Integer noOfCucumbers;
    private Integer noOfCucumberEaten;
    private Integer noOfRemainingCucumber;

    @Given("There are {int} cucumbers")
    public void cucumberTest_nrOne(Integer noOfCucumber) throws Throwable{
        noOfCucumbers = noOfCucumber;
    }

    @When("I eat {int} cucumbers")
    public void cucumberTest_nrTwo(Integer noOfCucumberEaten) throws Throwable{
        noOfCucumbers = noOfCucumbers - noOfCucumberEaten;
    }

    @Then("I should have {int} cucumbers")
    public void cucumberTest_nrThree(Integer noOfRemainingCucumber) throws Throwable{
        assertEquals(noOfCucumbers,noOfRemainingCucumber);
    }


}

虚拟特征

Feature: This is dummy test scenario
  Scenario Outline: Eating
  Given There are <start> cucumbers
  When I eat <eat> cucumbers
  Then I should have <left> cucumbers

  Examples:
  | start | eat | left |
  |  12   |  5  |  7   |
  |  20   |  5  |  15  |
  |  30   |  5  |  25  |

组装.xml

<assembly
    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
    <id>fat-tests</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>test</scope>
        </dependencySet>
    </dependencySets>
    <fileSets>
        <fileSet>
            <directory>${project.build.directory}/test-classes</directory>
            <outputDirectory></outputDirectory>
            <includes>
                <include>**/*.*</include>
               </includes>
            <useDefaultExcludes>true</useDefaultExcludes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}/test-classes</directory>
            <outputDirectory></outputDirectory>
            <includes>
                <include>*.feature</include>
            </includes>
            <useDefaultExcludes>true</useDefaultExcludes>
        </fileSet>
    </fileSets>
</assembly>

我已经尝试关注的一些资源

如果有人能帮助我,我将不胜感激。

我只是遇到了同样的问题,但问题是 Gradle。我试图从 jar 文件运行 Cucumber 测试,但遇到了相同的错误。

简答

在 build.gradle 中,我添加了下一个代码:

 shadowJar {
     ....
     transform(AppendingTransformer) {
        resource = 'META-INF/services/io.cucumber.core.backend.BackendProviderService'
     }
 }

Maven 中的类比是这样的:

<transformers>
    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
        <resource>META-INF/services/io.cucumber.core.backend.BackendProviderService</resource>
    </transformer>
</transformers>

稍微长一点的解释

调试了一段时间后(感谢 Yulia),我们发现了 cucumber 是如何寻找 Glue 的(Glue 类是 cucumber 运行所需的所有类——stepdef 类、contextconfigurator 等)。

它查找那些具有 BackendService(es) 的类,这些类的实例在某个时候被创建。

在成功案例中,实例化了 2 个服务:

  • io.cucumber.java.JavaBackendProviderService
  • io.cucumber.spring.SpringBackendProviderService

在失败的情况下(通过从 jar 运行调试发现)只有一个:

  • io.cucumber.java.JavaBackendProviderService

原来,它在这个文件中找到了要实例化的 BackendService - META-INF/services/io.cucumber.core.backend.BackendProviderService。

解包 jar 显示确实只列出了一项服务 - Java。

没有 Spring 后端服务实例化意味着它找不到 Spring 组件。

这些文件来自 cucumber 库:

  • Java 来自黄瓜-java
  • Spring 来自 cucumber-spring

所以归结为我们的打包过程无法将这两个文件合并在一起,它选择了第一个文件而不应用第二个文件。

从 IDE 运行时,它们似乎合并得很好。

所以添加上面的代码说打包任务(在我的例子中是 shadowJar)如何处理这个文件,添加一个规则来合并所有它会找到的这个名字的文件(当然在 META-INF 中)。

我希望你已经解决了你的问题,如果没有 - 我希望我的经验也能帮助你解决问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM