jbuddy
jbuddy

Reputation: 300

Run a spring-boot application and its cucumber tests in the same project using one maven "command"

Overview

A maven project using spring boot for which some cucumber tests are implemented (in the same project!).

src
 |
 |-main
 |  |
 |  |-java
 |     |
 |     |-SpringBootApp
 |     |-Controller
 |
 |-test
   |
   |-java
   |  |
   |  |-cucumbertests
   |       |     
   |       |-StepDefinitions
   |       |-CucumberTestsRunner
   |
   |-resources
        |-features
              |-hello.feature

Controller

@RestController
@RequestMapping("/")
public class Controller {

    @GetMapping("hello")
    public String hello() {
        return "Hello!";
    }
}

CucumberTestsRunner

@RunWith(Cucumber.class)
@CucumberOptions(glue = "cucumbertests")
pulic class CucumberTestsRunner {
}

StepDefinitions

public class StepDefinitions {

    private String response;

    @When("I say hello")
    public void iSayHello() {
        // rest assured call
        response = get("<base_url>/hello").extract().asString();
    }

    @Then
    public void iMGreetedWithHello() {
        assertEquals("Hello!", response);
    }
}

With this in place,

So far so good, the tests pass without any issue.

Problem

I'd like to be able to issue a single command to start the SpringBoot application and then run the tests against the started application. Then after the tests finished, kill the SpringBoot application.

Ideally this is intended to be used in a CI system like Jenkins.

I was exploring the Apache Maven AntRun plugin as an option, but this is my first time doing this kind of set up and I'm not sure this would be a right approach. Previously I have seen set up like this but on independent projects (tests in a different app than the tested application).

Upvotes: 2

Views: 7624

Answers (2)

M.P. Korstanje
M.P. Korstanje

Reputation: 12049

As an alternative to using mvn spring-boot:start test spring-boot:stop or to using mvn verify and starting the application in the pre-integration-test and stopping it in the post-integration-test phase you can also use cucumber-spring and run the test with Mock MCV.

├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── com
    │           └── example
    │               └── Application.java
    └── test
        ├── java
        │   └── com
        │       └── example
        │           └── CucumberTest.java
        └── resources
            ├── com
            │   └── example
            │       └── hello.feature
            └── junit-platform.properties

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>com.example</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <properties>
        <java.version>11</java.version>
        <cucumber.version>6.5.0</cucumber.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>${cucumber.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-spring</artifactId>
            <version>${cucumber.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-junit-platform-engine</artifactId>
            <version>${cucumber.version}</version>
            <scope>test</scope>
        </dependency>

    </dependencies>
</project>
package com.example;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class Application {

    @RestController
    public static class HelloController {

        @RequestMapping("/")
        public String local() {
            return "Greetings from Local!";
        }

    }

}

package com.example;

import io.cucumber.java.en.Given;
import io.cucumber.junit.platform.engine.Cucumber;
import io.cucumber.spring.CucumberContextConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@Cucumber
@CucumberContextConfiguration
@SpringBootTest
@AutoConfigureMockMvc
public class CucumberTest {

    @Autowired
    private MockMvc mvc;

    @Given("the application says hello")
    public void getLocalHello() throws Exception {
        mvc.perform(get("/").accept(APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("Greetings from Local!")));
    }

}

Feature: Hello world

  Scenario: Calling a rest end point
    * the application says hello

Upvotes: 3

Ken S
Ken S

Reputation: 236

Instead of using spring-boot:run in one console and running your tests in a second one, you can use use spring-boot:start and spring-boot:stop.

Something like mvn spring-boot:start test spring-boot:stop would start the application, run the tests and then stop the application again.

Upvotes: 2

Related Questions