J'écris une nouvelle application et j'essaie de faire du BDD avec concombre et Spring Boot 1.4. Le code de travail est comme indiqué ci-dessous:
@SpringBootApplication
public class Application {
@Bean
MyService myService() {
return new MyService();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
public class MyService {}
Le code de test est comme indiqué ci-dessous:
@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");
}
}
Le fichier de fonctionnalités est comme indiqué ci-dessous:
Feature: Test Cucumber with spring
Scenario: First Scenario
Given Some initial condition
Then Nothing happens
Lorsque j'exécute le programme ci-dessus tel quel, tout fonctionne correctement et la dépendance (MyService) est injectée dans MyStepDef sans aucun problème.
Si je remplace ce code:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Application.class, loader = SpringApplicationContextLoader.class)
Avec le code ci-dessous (Nouvelle façon de le gérer dans Spring Boot 1.4):
@RunWith(SpringRunner.class)
@SpringBootTest
Ensuite, la dépendance (MyService) n'est jamais injectée. Est-ce que je manque quelque chose peut-être?
Merci d'avance pour votre aide!!!
J'ai eu le même problème. Le commentaire ci-dessus m'a dirigé vers la solution
Le code problématique dans concombre-printemps semble être celui-ci github.com/cucumber/cucumber-jvm/blob/master/spring/src/main /…
Après avoir ajouté l'annotation @ContextConfiguration
, les tests fonctionnent comme prévu.
Donc, ce que j'ai est la suivante ...
@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;
[...]
}
J'espère que cela vous aide plus loin
Je l'ai eu avec Spring Boot 1.5.x et 2.0 puis a écrit un article de blog pour tenter de clarifier cela, car c'est délicat.
Premièrement, même si c'est évident, vous devez avoir les bonnes dépendances incluses dans votre projet (étant cucumber-spring
l'important ici). Par exemple, avec 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>
Maintenant, la partie importante pour que cela fonctionne, résume:
@RunWith(Cucumber.class
. @Given
, @When
, @Then
, etc.). @SpringBootTest
, @RunWith(SpringRunner.class)
et toute autre configuration nécessaire pour exécuter votre test avec Spring Boot. Par exemple, si vous implémentez un test d'intégration sans vous moquer d'autres couches, vous devez ajouter la configuration webEnvironment
et la définir sur RANDOM_PORT
ou DEFINED_PORT
. Voir le schéma et le squelette de code ci-dessous.
Le point d'entrée:
@RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/resources/features/bag.feature", plugin = {"pretty", "html:target/cucumber"})
public class BagCucumberIntegrationTest {
}
La classe de test de base Spring Boot:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public abstract class SpringBootBaseIntegrationTest {
}
La classe des définitions d'étape:
@Ignore
public class BagCucumberStepDefinitions extends SpringBootBaseIntegrationTest {
// @Given, @When, @Then annotated methods
}
C’est ce dont vous avez besoin pour faire fonctionner l’ID. Pour un exemple de code complet, vérifiez simplement my blog post ou le code dans GitHub .
Avant Spring Boot 1.4, vous pouvez utiliser
@ContextConfiguration(classes = {YourSpringConfiguration.class}, loader = SpringApplicationContextLoader.class)
À partir de Spring Boot 1.4, SpringApplicationContextLoader est obsolète. Vous devez donc utiliser SpringBootContextLoader.class à la place.
Ajouter simplement @SpringBootTest (avec une classe de configuration facultative) devrait fonctionner de manière autonome, mais si vous regardez le code dans cucumber.runtime.Java.spring.SpringFactory, la méthode annotatedWithSupportedSpringRootTestAnnotations ne vérifie pas cette annotation, ce qui explique pourquoi Une annotation en conjonction avec @SpringBootTest fonctionne.
En réalité, le code concombre-printemps doit changer. Je vais voir si je peux soulever un problème, car dans la documentation de Spring, il est indiqué que SpringApplicationContextLoader ne doit être utilisé qu'en cas d'absolue nécessité. Je vais essayer de soulever un problème à ce sujet pour le support de ressort de concombre.
La réponse de stripwire en combinant @SpringBootTest et @ContextConfiguration est donc la meilleure solution de contournement.
Je l'ai travailler dans Spring Boot 1.5. Je veux partager la configuration avec vous:
<?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)
}
}
Ceci est ma configuration, vous pouvez l'essayer
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ContextConfiguration(classes = {Application.class})