Spring 启动 WebFlux 测试未找到 MockMvc

Spring Boot WebFlux test not finding MockMvc

问题

我正在尝试 运行 一个简单的 spring 启动测试,但我收到的错误表明它无法在 运行 时间进行 MockMvc。文档表明我使用了正确的注释,并且我使用 start.spring.io 创建了我的 pom.xml。不确定为什么会出现问题。

错误:

 No qualifying bean of type 'org.springframework.test.web.servlet.MockMvc'

测试代码

import org.junit.Test;
import org.junit.runner.RunWith;
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.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MyWebApplicationTests {

    @Autowired
    MockMvc mockMvc;

    @Test
    public void Can_Do_Something() throws Exception {
        mockMvc.perform(get("/hello-world")).andDo(print()).andExpect(status().isOk())
                .andExpect(content().string(containsString("Hello World")));
    }

}

文档:

我将此文档用作参考 -> https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-with-mock-environment

POM.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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>

    <groupId>com.mywebapp</groupId>
    <artifactId>webapp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>my-webapp</name>
    <description>Backend application</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.M1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>10</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>3.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.6</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>


</project>

正如 M.Deinum MockMvc 所指出的那样,没有为 Spring Boot 中的 WebFlux 配置加载。您需要改用 WebTestClient。因此,将 AutoConfigureMockMvc 替换为 AutoConfigureWebTestClient 并在其位置使用 webTestClient 方法。

需要注意的一件事是,这是在幕后进行实际的网络调用,并将启动服务器。 MockMVC 不启动服务器。 What is the difference between MockMvc and WebTestClient?

当人们在切换到 Spring WebFlux 后试图测试他们的端点时,这个问题似乎出现在搜索列表的顶部,我将在此处添加我能够确定的内容。 (应该注意的是,在过去,我很难让 WebTestClientRestController 带注释的端点一起运行。但这段代码有效。我想我缺少一个依赖项,它不是不清楚。)

MyService.java

@Service
public class MyService {
     public String doSomething(String input) {
         return input + " implementation";
     }
}

MyController.java

@RestController
@RequestMapping(value = "/api/v1/my")
public class MyController {
    @Autowired
    private MyService myService;

    @RequestMapping(value = "", method = RequestMethod.POST, consumes = {APPLICATION_JSON_VALUE})
    public ResponseEntity<Mono<String>> processPost(@RequestBody String input)
    {
        String response = myService.doSomething(input);
        return ResponseEntity.ok(Mono.just(response));
    }

测试MyController.java

@ExtendWith(SpringExtension.class)
@WebFluxTest(MyController.class)
public class TestMyController {
    @Autowired
    private WebTestClient webTestClient;

    @MockBean
    private MyService myService;

    @Test
    public void testPost() throws Exception {
          // Setup the Mock MyService. Note the 'mocked' vs 'implementation' 
          when(myService.doSomething(anyString())).thenAnswer((Answer<String>) invocation -> {
               String input = invocation.getArgument(0);
               return input + " mocked";
          });

          String response = webTestClient.post()
                .uri("/api/v1/my")
                .body(BodyInserters.fromObject("is"))
                .accept(MediaType.APPLICATION_JSON)
                .exchange()
                .expectStatus().isOk()
                .returnResult(String.class)
                .getResponseBody()
                .blockFirst();
          assertThat(response).matches("is mocked");
    }
}

可能导致难以诊断的问题的依赖项似乎来自 reactor-test。因此,如果 WebTestClient 不工作,请确保依赖项存在。

pom.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
        <version>2.1.5.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <version>2.1.5.RELEASE</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <version>3.2.9.RELEASE</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <artifactId>jackson-module-kotlin</artifactId>
                <groupId>com.fasterxml.jackson.module</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.4.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.google.truth</groupId>
        <artifactId>truth</artifactId>
        <version>0.45</version>
        <scope>test</scope>
    </dependency>