Spring Boot @WebMvcTest 具有 @MockBean null - 使用 SpringRunner 有效

Kas*_*too 2 spring-boot junit5

简而言之: 从 Junit4 迁移到 JUnit5 存在困难。删除后,@RunWith(SpringRunner.class)我的@MockBean注释服务为空,尽管我使用的是“@WebMvcTest”。为什么它不起作用?

long: 几天来我一直在努力解决这个问题。我正在对我的 Spring Boot 应用程序进行一些测试,使用@RunWith(SpringRunner.class)im 与@WebMvcTest.

由于那是 JUnit4,我试图迁移到 Junit5。我从 pom 中删除了 vintage 依赖项,并添加了spring-boot-starter-test. JUnit 5 只剩下依赖项了junit-jupiter。

我读了一些关于这方面的帖子和示例。由于我不想加载完整的上下文,SpringBootTest 不是这样的方式(并且根本不起作用),我“认为”我发现这@WebMvcTest已经足够了,因为它已经包含@extendWith与 JUnit5 等效的注释@RunWith(SpringRunner.class)。所以:我只需要删除 springRunner 就可以了。

但是删除那一行后,我的带有 @MockBean 注释的服务从现在开始为空。我可以找到许多仅使用@WebMvcTest和 的示例@MockBean。所以我不明白,为什么我的不起作用。添加@RunWith(SpringRunner.class)使其再次工作。

这就是测试类(没有 springrunner):

package my.package;

import com.fasterxml.jackson.databind.ObjectMapper;
import my.package.controller.SkillTileCommand;
import my.package.controller.SkillTileController;
import my.package.controller.SkillTileResponse;
import my.package.service.SkillTileService;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import java.util.List;

import static org.hamcrest.Matchers.hasSize;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.doNothing;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(SkillTileController.class)
public class SkillTileControllerIntegrationTest {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private SkillTileService skillTileService;

    private final SkillTileTestDataFactory testDataFactory = new SkillTileTestDataFactory();

    @Test
    public void givenSkillTiles_whenGETFindAll_thenReturnJsonArray() throws Exception {

        List<SkillTileResponse> skillTiles = testDataFactory.createTestSkillTileResponses(1, true, null, true);
        SkillTileResponse st1 = skillTiles.get(0);

        given(skillTileService.findAll(null)).willReturn(skillTiles);

        mvc.perform(get("/skill-tile/")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$", hasSize(1)))
                .andExpect(jsonPath("$[0].name").value(st1.getName()));
    }
}
Run Code Online (Sandbox Code Playgroud)

相反,使用 Spring runner 的工作方式如下:

package my.package;

import com.fasterxml.jackson.databind.ObjectMapper;
import my.package.controller.SkillTileCommand;
import my.package.controller.SkillTileController;
import my.package.controller.SkillTileResponse;
import my.package.service.SkillTileService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import java.util.List;

import static org.hamcrest.Matchers.hasSize;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.doNothing;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class)
@WebMvcTest(SkillTileController.class)
public class SkillTileControllerIntegrationTest {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private SkillTileService skillTileService;
[...]
}
Run Code Online (Sandbox Code Playgroud)

May服务负责人也感兴趣:

package my.package.service;

import lombok.RequiredArgsConstructor;
import my.package.controller.SkillTileCommand;
import my.package.controller.SkillTileResponse;
import my.package.exception.ResourceNotFoundException;
import my.package.repository.SkillTileEntity;
import my.package.repository.SkillTileRepository;
import my.package.utils.ObjectMapper;
import my.package.utils.ResourceUtility;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@RequiredArgsConstructor
@Service
public class SkillTileService {

    private final SkillTileRepository skillTileRepository;
[...]
}
Run Code Online (Sandbox Code Playgroud)

以下是与测试相关的两个依赖项:

    [...]
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.8.2</version>
        <scope>test</scope>
    </dependency>
    [...]
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助。如果不只停留在 JUnit4 就好了。

编辑:我对另一个测试类也有相同的行为,该测试类仅用注释@DataJpaTest并具有@Autowire字段。他们的零没有@RunWith

M. *_*num 8

如果您仔细查看测试,您会发现您的@Test注释仍然来自旧org.junit包。这是 JUnit4。这意味着您的测试实际上是使用 JUnit4 而不是 JUnit5 运行的。这基本上忽略了所有注释,因此也忽略了@WebMvcTest.

要修复此问题,请确保您的@Test注释也来自正确的org.junit.jupiter.api包,以使其成为正确的 JUnit5 测试。