spring-bootcucumberjunit5cucumber-javacucumber-spring

Reusing Cucumber SpringBoot Tests for local and remote integration tests


I have below setup

I am able to run cucumber test with below configuration to test SpringBoot Application running locally using maven failsafe plugin.

Note: The configuration uses @SpringBootTest annotation to start the SubjectUnderTest(SUT) before the running the Test.

@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example.bdd.stepdefs")
@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME,
    value = "pretty," +
     "html:target/tests-reports/report.html," +
     "json:target/tests-reports/report.json," +
     "junit:target/tests-reports/cucumber-junit.xml,")
@CucumberContextConfiguration
@ActiveProfiles("local")
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class FunctionalIT {
} 

My Requirements:

  1. Reuse the same cucumber tests to validate the springboot application started using the @SpringBootTest during the maven integration test, as well as testing the deployed application on remote environments (e.g. qa, prod)
  2. Leverage Spring application-env.properties files and profiles for the environment specific configuration.
  3. Only start the minimum required Spring ApplicationContext depending on the test to be run against the local app (@SpringBootTest) vs remote app (No @SpringBootTest annotation).
  4. Specify the active profile as needed e.g. -Dspring.profiles.active=local or -Dspring.profile.active=qa. And only that profile should be used by the Spring.

I tried few options without much success so far, I faced below issues:

  1. Tried createing another test class for remote environments without @SpringBootTest annotation, but @CucumberContextConfiguration is only allowed on single class.
  2. If I separate all cucumber config in its own class, the junit is not running the cucumber tests. Aparently @CucumberContextConfiguration needs to be applied on @SpringBootTest or @ContextConfiguration only.

Any idea how to get the setup working for the above requirements ?


Solution

  • I solved the problem with the below changes.

    1. Custom Annotation for common cucumber configuration
    package com.example.bdd.config;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Suite
    @IncludeEngines("cucumber")
    @SelectClasspathResource("features")
    @CucumberContextConfiguration
    @ConfigurationParameter(key = PLUGIN_PROPERTY_NAME,
        value = "pretty," +
         "html:target/tests-reports/report.html," +
         "json:target/tests-reports/report.json," +
         "junit:target/tests-reports/cucumber-junit.xml")
    public @interface CucumberTestSuite {
        
    }
    
    1. Test runner for testing SUT (setup using @SpringBootTest) for local/ci builds.
    package com.example.bdd.env.test;
    
    @CucumberTestSuite
    @ConfigurationParameter(key = GLUE_PROPERTY_NAME, 
        value = "com.example.bdd.stepdefs," + 
                "com.example.bdd.env.test")
    @ContextConfiguration(initializers = ApplicationInitializer.class)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    @ActiveProfiles("test")
    public class ComponentIT {
    }
    
    # Note: ApplicationInitializer takes care of spinning up required dependencies (mocks/stubs) for the Component Testing. 
    
    1. Test runner for testing SUT in a remote QA environment
    package com.example.bdd.env.acceptance;
    
    @CucumberTestSuite
    @ConfigurationParameter(key = GLUE_PROPERTY_NAME, 
        value = "com.example.bdd.stepdefs," + 
                "com.example.bdd.env.acceptance")
    @ContextConfiguration
    @TestPropertySource("classpath:application-${env}.properties")
    @ActiveProfiles("${env}")
    public class AcceptanceIT {
    }
    
    1. different maven profiles in pom.xml
      <profiles>
        <profile>
          <id>default</id>
          <activation>
            <activeByDefault>true</activeByDefault>
          </activation>
          <build>
            <plugins>
              <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <configuration>
                  <excludes>
                    <exclude>**/*AcceptanceIT.java</exclude>
                  </excludes>
                </configuration>
              </plugin>
            </plugins>
          </build>
        </profile>
        <profile>
          <id>acceptance-tests</id>
          <properties>
            <skip.surefire.tests>true</skip.surefire.tests>
          </properties>
          <build>
            <plugins>
              <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <configuration>
                  <includes>
                    <include>**/*AcceptanceIT.java</include>
                  </includes>
                </configuration>
              </plugin>
            </plugins>
          </build>
        </profile>
      </profiles>
    
    

    Now for running

    1. mvn clean verify runs unit tests and ComponentIT by default (for local and CI environment)
    2. mvn clean verify -P acceptance-tests -Denv=qa runs AcceptanceIT tests on qa environment, like wise -Denv=stage or -Denv=prod to run tests against the stage and prod environments respectively.