Search code examples
springspring-bootcucumberspring-boot-testcucumber-junit

How to stop @CucumberContextConfiguration with @SpringBootTest from reloading application context between every test?


I've got this problem where my application context is reloaded between every test. I'm wiring in my actual application with functional test properties, wiremock etc. to create a functional test environment. Tests have always run fine but now we've added several it's become painfully slow due to the spring application being re-run everytime. The io.cucumber versions I'm using in my pom for cucumber-spring, cucumber-java, cucumber-junit is 7.11.1. My Functional Test runner is annotated like this:

@RunWith(Cucumber.class)
@CucumberOptions(
    features = "classpath:functional/features",
    glue = {"com.iggroup.ds.functional.stepdefinitions"},
    monochrome = true,
    tags = "@FunctionalTest",
    plugin = {"pretty", "html:target/cucumber-html-report", "junit:target/cucumber-xml-report.xml"}
)
public class FunctionalTestRunner {

    @BeforeClass
    public static void beforeClass() {
        prepareEnvironment();
    }

    private static void prepareEnvironment() {
        int applicationPort = SocketUtils.findAvailableTcpPort();
        System.setProperty("server.port", String.valueOf(applicationPort));
        System.setProperty("spring.active.profiles", "FUNCTIONAL_TEST");
        System.setProperty("spring.cloud.config.enabled", "false");
        System.setProperty("spring.cloud.config.server.bootstrap", "false");
    }
}

Inside my glue package the Cucumber Configuration looks like this:

@AutoConfigureWireMock(port = 8089)
@CucumberContextConfiguration
@SpringBootTest(
    classes = {
        ServiceApplication.class,
        RestClients.class
    },
    webEnvironment = DEFINED_PORT,
    properties = {
        "spring.profiles.active=FUNCTIONAL_TEST",
        "spring.cloud.config.enabled = false"
    }
)
public class FunctionalTestSpringCucumberConfiguration {
}

And lastly the application itself looks like this:

@EnableAsync
@EnableCaching
@EnableConfigServer
@SpringBootApplication
@EnableConfigurationProperties
public class ServiceApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }
}

I had read somewhere before that the presence of @MockBean was causing unexpected refreshes between context although I never found out as to why - but I have none defined. As far as I can tell across the articles I've been reading, this shouldn't refresh my context every time so wondering if there's any way I can force it not to rewire the ServiceApplication.class in between every scenario?


Solution

  • @AutoConfigureWireMock(port = 8089)
    

    By using Wiremock on fixed port you are dirtying the application context. This means a new application context will be created for each test. The code responsible for this prints a warning that you can see in your logs.

    if (portIsFixed(testContext)) {
        if (log.isWarnEnabled()) {
            log.warn("You've used fixed ports for WireMock setup - "
                + "will mark context as dirty. Please use random ports, as much "
                + "as possible. Your tests will be faster and more reliable and this "
                + "warning will go away");
        }
        testContext.markApplicationContextDirty(DirtiesContext.HierarchyMode.EXHAUSTIVE);
    }