带有Spring Boot 1.4的黄瓜:使用@SpringBootTest和@RunWith(SpringRunner.class)时未注入的依赖项

时间:2016-08-08 18:42:57

标签: java spring-boot cucumber-jvm

我正在编写一个新的应用程序并尝试使用黄瓜和Spring Boot 1.4进行BDD。工作代码如下所示:

<ion-view view-title="Dashboard">
  <ion-content class="padding">
    <h2>Welcome to Ionic</h2>
     <input ng-model="getUserName" ng-change="nameChange()"  name="anim" class="my-input"
         aria-describedby="inputDescription" />
    <p>
    This is the Ionic starter for tabs-based apps. For other starters and ready-made templates, check out the <a href="http://market.ionic.io/starters" target="_blank">Ionic Market</a>.
    </p>
    <p>
      To edit the content of each tab, edit the corresponding template file in <code>www/templates/</code>. This template is <code>www/templates/tab-dash.html</code>
    </p>
    <p>
    If you need help with your app, join the Ionic Community on the <a href="http://forum.ionicframework.com" target="_blank">Ionic Forum</a>. Make sure to <a href="http://twitter.com/ionicframework" target="_blank">follow us</a> on Twitter to get important updates and announcements for Ionic developers.
    </p>
    <p>
      For help sending push notifications, join the <a href="https://apps.ionic.io/signup" target="_blank">Ionic Platform</a> and check out <a href="http://docs.ionic.io/docs/push-overview" target="_blank">Ionic Push</a>. We also have other services available.
    </p>
  </ion-content>
</ion-view>

测试代码如下所示:

var str = "ATOM LEU 0.1234 C 0.123 0.32 0.34";
var strExp = str.split(" ");
var newStr = str.replace(strExp[3], "&");
console.log(newStr);

功能文件如下所示:

@SpringBootApplication
public class Application {
    @Bean
    MyService myService() {
        return new MyService();
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

public class MyService {}

当我按原样运行上述内容时,一切正常,并且依赖项(MyService)被注入到MyStepDef中而没有任何问题。

如果我替换此代码:

@RunWith(Cucumber.class)
public class RunFeatures {}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Application.class, loader = SpringApplicationContextLoader.class)
public class MyStepDef {
    @Autowired
    MyService myService;

    @Given("^Some initial condition$")
    public void appIsStarted() throws Throwable {
        if (service == null) throw new Exception("Dependency not injected!");
        System.out.println("App started");
    }

    @Then("^Nothing happens$")
    public void thereShouldBeNoException() throws Throwable {
        System.out.println("Test passed");
    }
}

使用下面的代码(在Spring Boot 1.4中处理它的新方法):

Feature: Test Cucumber with spring
    Scenario: First Scenario
        Given Some initial condition
        Then Nothing happens

然后依赖(MyService)永远不会被注入。我可能错过了什么吗?

先谢谢你的帮助!!!

5 个答案:

答案 0 :(得分:16)

我遇到了同样的问题。上面的评论指导我解决方案

  

黄瓜弹簧中有问题的代码似乎是这个github.com/cucumber/cucumber-jvm/blob/master/spring/src/main / ...

添加注释@ContextConfiguration后,测试按预期工作。

所以我得到的是以下内容......

@RunWith(Cucumber.class)
@CucumberOptions(plugin = {"json:target/cucumber.json", "pretty"}, features = "src/test/features")
public class CucumberTest {
}

@ContextConfiguration
@SpringBootTest
public abstract class StepDefs {
}

public class MyStepDefs extends StepDefs {

    @Inject
    Service service;

    @Inject
    Repository repository;

    [...]

}

我希望这可以帮助你进一步

答案 1 :(得分:4)

我使用Spring Boot 1.5.x和2.0然后wrote a blog post来解决这个问题,因为它很棘手。

首先,即使很明显,您也需要在项目中包含正确的依赖项(cucumber-spring是重要的依赖项)。例如,使用Maven:

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-java</artifactId>
    <version>2.3.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-junit</artifactId>
    <version>2.3.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-spring</artifactId>
    <version>2.3.1</version>
    <scope>test</scope>
</dependency>

现在,使其成功的重要部分归纳为:

  • 您的测试的入口点应该是使用@RunWith(Cucumber.class注释的类。
  • 此类将使用步骤定义,这些步骤定义通常位于带有注释方法的分隔类中(@Given@When@Then等)。
  • 诀窍是这个类应该扩展一个用@SpringBootTest注释的基类,@RunWith(SpringRunner.class)以及使用Spring Boot运行测试所需的任何其他配置。例如,如果您在不模仿其他图层的情况下实施集成测试,则应添加webEnvironment配置并将其设置为RANDOM_PORTDEFINED_PORT

请参阅下面的图表和代码框架。

TPD - Using DI with Cucumber in Spring Boot

切入点:

@RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/resources/features/bag.feature", plugin = {"pretty", "html:target/cucumber"})
public class BagCucumberIntegrationTest {
}

Spring Boot基础测试类:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public abstract class SpringBootBaseIntegrationTest {
}

步骤定义类:

@Ignore
public class BagCucumberStepDefinitions extends SpringBootBaseIntegrationTest {
  // @Given, @When, @Then annotated methods
}

这是让DI工作所需要的。有关完整的代码示例,请选中my blog postcode in GitHub

答案 2 :(得分:2)

在Spring Boot 1.4之前,您可以使用

@ContextConfiguration(classes = {YourSpringConfiguration.class}, loader = SpringApplicationContextLoader.class)

从Spring Boot 1.4开始,不推荐使用SpringApplicationContextLoader,因此您应该使用SpringBootContextLoader.class

真的只是添加@SpringBootTest(带有一个可选的配置类)应该可以独立工作,但是如果你看看cucumber.runtime.java.spring.SpringFactory方法中的代码annotatedWithSupportedSpringRootTestAnnotations它没有检查那个注释这就是为什么简单地将注释与@SpringBootTest一起添加的原因。

黄瓜春天的代码真的需要改变。我将看看是否可以引发一个问题,就像在Spring文档中一样,它声明SpringApplicationContextLoader只应该在绝对必要时使用。我会尝试为黄瓜弹簧支持提出一个问题。

因为使用@SpringBootTest和@ContextConfiguration的组合代表stripwire的答案是最好的解决方法。

答案 3 :(得分:0)

这是我的配置,你可以尝试一下

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ContextConfiguration(classes = {Application.class})

答案 4 :(得分:0)

我在Spring Boot 1.5中使用它。我想与您分享配置:

的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        ...
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

        ...
    <dependencies>
            ...
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>1.2.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-spring</artifactId>
            <version>1.2.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>1.2.5</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
        ...
</project>

功能文件

Feature: User should be greeted

  Background:
    Given The database is empty
    Then All connections are set

  Scenario: Default user is greeted
    Given A default user
    When The application is started
    Then The user should be greeted with "Hello Marc!"

黄瓜钩

@RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/resources", strict = true)
public class CucumberTests {    // Classname should end on *Tests

}

抽象弹簧配置

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration
abstract class AbstractSpringConfigurationTest {

}

class CucumberGlue : AbstractSpringConfigurationTest() {

    @Autowired
    lateinit var restTemplate: TestRestTemplate

    @Autowired
    lateinit var restController: RestController

    @Autowired
    lateinit var personRepository: PersonRepository

    @Autowired
    lateinit var entityManager: EntityManager

    private var result: String? = null

    @Given("^The database is empty$")
    fun the_database_is_empty() {
        personRepository.deleteAll()
    }

    @Then("^All connections are set$")
    fun all_connections_are_set() {
        assertThat(restTemplate).isNotNull()
        assertThat(entityManager).isNotNull()
    }

    @Given("^A default user$")
    fun a_default_user() {
    }

    @When("^The application is started$")
    fun the_application_is_started() {
        result = restController.testGet()
    }

    @Then("^The user should be greeted with \"([^\"]*)\"$")
    fun the_user_should_be_greeted_with(expectedName: String) {
        assertThat(result).isEqualTo(expectedName)
    }

}