运行 spring-boot 应用程序及其 cucumber 在同一项目中使用一个 maven "command" 进行测试

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

概览

A maven 项目使用 spring boot 一些 cucumber 测试已实施(在同一个项目中!)。

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

控制器

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

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

CucumberTestsRunner

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

步骤定义

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);
    }
}

有了这个,

到目前为止一切顺利,测试顺利通过。

问题

我希望能够发出 单个命令 来启动 SpringBoot 应用程序,然后 运行 针对已启动的应用程序进行测试。然后在测试完成后,杀掉SpringBoot应用。

理想情况下,这旨在用于像 Jenkins 这样的 CI 系统。

我正在探索 Apache Maven AntRun plugin 作为一个选项,但这是我第一次进行这种设置,我不确定这是否是正确的方法。以前我见过这样的设置,但在独立项目上(在与测试应用程序不同的应用程序中进行测试)。

您可以使用 spring-boot:start and spring-boot:stop.[=12=,而不是在一个控制台中使用 spring-boot:运行 并在第二个控制台中 运行 进行测试]

类似 mvn spring-boot:start test spring-boot:stop 的东西会启动应用程序,运行 测试然后再次停止应用程序。

作为使用 mvn spring-boot:start test spring-boot:stop 或使用 mvn verify 并在 pre-integration-test 阶段启动应用程序并在 post-integration-test 阶段停止应用程序的替代方法,您还可以使用 cucumber-spring 和 运行 模拟 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