9

I'm using spring boot as it removes all the boring stuff and let's me focus on my code, but all the test examples use junit and I want to use cucumber?

Can someone point me in the right direction to get cucumber and spring to start things up, do all the auto config and wiring and let my step definitions use auto wired beans to do stuff?

Zac Tolley
  • 2,340
  • 4
  • 19
  • 22

4 Answers4

17

Try to use the following on your step definition class:

@ContextConfiguration(classes = YourBootApplication.class, 
                      loader = SpringApplicationContextLoader.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class MySteps {
    //...
}

Also make sure you have the cucumber-spring module on your classpath.

Boris Pavlović
  • 63,078
  • 28
  • 122
  • 148
  • @PedroLopez Could this find the story files? At my build the stories are not executed. The problem is if you use Cucumber.class as runner the stories are found but the tomcat is not startet, if you use the SpringJUnit4ClassRunner the tomcat ist startet but the stories are not executed. There is a open enhancement: https://github.com/spring-projects/spring-boot/issues/2525 Do you have not this problem? – Huluvu424242 Feb 28 '15 at 17:57
  • The Cucumber runner must be used in a different class (in your Runner class, in fact), this is for your Step Definition. The only thing is to annotate this class with @Ignore to prevent it to run as a unit test as well, when running your whole test suite. Hope this helps. – Pedro Lopez Mar 01 '15 at 09:29
  • 2
    This works even for web tests! You can add **@WebIntegrationTest({"server.port=9794", "management.port=0"})** annotation as well and the configured container will start and let you run your Web Integration tests. – Altair7852 Apr 19 '15 at 22:50
  • This works really well, thanks for the reply. What happens if you have multiple Step Definition classes that all want to run against the same Spring Boot application ? How do you prevent the application being loaded for each step definition class (we want it loaded once for the entire suite). – PaulNUK May 13 '15 at 08:52
  • @PaulNUK Did you ever figure it out? – jakehschwartz Jun 04 '15 at 19:33
  • In order to stop multiple contexts being loaded (see my comment above) and to allow access to web related mocks, I added additional annoations: – PaulNUK Jun 09 '15 at 09:19
2

Jake - my final code had the following annotations in a superclass that each cucumber step definition class extended, This gives access to web based mocks, adds in various scopes for testing, and bootstraps Spring boot only once.

@ContextConfiguration(classes = {MySpringConfiguration.class}, loader = SpringApplicationContextLoader.class)
@WebAppConfiguration
@TestExecutionListeners({WebContextTestExecutionListener.class,ServletTestExecutionListener.class})

where WebContextTestExecutionListener is:

public class WebContextTestExecutionListener extends
        AbstractTestExecutionListener {

    @Override
    public void prepareTestInstance(TestContext testContext) throws Exception {

        if (testContext.getApplicationContext() instanceof GenericApplicationContext) {
            GenericApplicationContext context = (GenericApplicationContext) testContext.getApplicationContext();
            ConfigurableListableBeanFactory beanFactory = context
                    .getBeanFactory();
            Scope requestScope = new RequestScope();
            beanFactory.registerScope("request", requestScope);
            Scope sessionScope = new SessionScope();
            beanFactory.registerScope("session", sessionScope);
        }
    }
}
PaulNUK
  • 4,774
  • 2
  • 30
  • 58
  • 1
    Hey sorry, it took me so long to get back to you. I put up too much reputation and I wasn't able to post. I was able to get it working in a sample project without the TestExecutionListeners but Im having a problem in my main project around @EnableAutoConfiguration(exclude={RabbitAutoConfiguration.class}) which seems unrelated. Thanks for all the help though. – jakehschwartz Jun 11 '15 at 18:38
1

My approach is quite simple. In a Before hook (in env.groovy as I am using Cucumber-JVM for Groovy), do the following.

package com.example.hooks

import static cucumber.api.groovy.Hooks.Before
import static org.springframework.boot.SpringApplication.exit
import static org.springframework.boot.SpringApplication.run

def context

Before {
    if (!context) {
        context = run Application

        context.addShutdownHook {
            exit context
        }
    }
}
adarshr
  • 61,315
  • 23
  • 138
  • 167
0

Thanks to @PaulNUK, I found a set of annotations that will work.

I posted the answer in my question here

My StepDefs class required the annotations: @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = DemoApplication.class, loader = SpringApplicationContextLoader.class) @WebAppConfiguration @IntegrationTest

There is also a repository with source code in answer I linked.

jakehschwartz
  • 1,005
  • 2
  • 13
  • 32