web-dev-qa-db-ja.com

Spring Boot 1.4を使用したキュウリ:@SpringBootTestおよび@RunWith(SpringRunner.class)を使用すると依存関係が注入されません

新しいアプリを作成していて、キュウリとSpring Boot1.4を使用してBDDを実行しようとしています。動作するコードは次のとおりです。

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

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

public class MyService {}

テストコードは次のとおりです。

@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");
    }
}

機能ファイルは次のとおりです。

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

上記をそのまま実行すると、すべてが正常に機能し、依存関係(MyService)が問題なくMyStepDefに挿入されます。

このコードを置き換えると:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Application.class, loader = SpringApplicationContextLoader.class)

以下のコードで(Spring Boot 1.4でそれを処理する新しい方法):

@RunWith(SpringRunner.class)
@SpringBootTest

その後、依存関係(MyService)が注入されることはありません。私はおそらく何かが足りないのですか?

よろしくお願いします!!!

13
Aliyu Fonyuy

私も同じ問題を抱えていました。上からのコメントは私を解決策に導きました

Cucumber-springの問題のあるコードは、この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;

    [...]

}

これがさらにお役に立てば幸いです

16
stripfire

Spring Boot 1.5.xと2.0で動作するようにした後、 ブログ投稿を書いた トリッキーなので、これを明確にしようとしました。

まず、明らかな場合でも、プロジェクトに適切な依存関係を含める必要があります(ここでは_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)、およびSpringBootでテストを実行するために必要なその他の構成で注釈が付けられた基本クラスを拡張する必要があることです。たとえば、他のレイヤーをモックせずに統合テストを実装する場合は、webEnvironment構成を追加し、それを_RANDOM_PORT_または_DEFINED_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を機能させるために必要なものです。完全なコード例については、 私のブログ投稿 または GitHubのコード を確認してください。

4
Moisés

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は絶対に必要な場合にのみ使用する必要があると記載されているため、問題を提起できるかどうかを確認します。キュウリのSpringサポートについては、この問題を提起します。

したがって、現状では、@ SpringBootTestと@ContextConfigurationの組み合わせを使用したstripwireの答えが最善の回避策です。

2
PaulNUK

Spring Boot1.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

}

抽象Spring構成

@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)
    }

}
0
Marc Enschede

これは私の構成です、あなたはそれを試すことができます

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