Spring Boot @WebMvcTest与@SpringBootTest的区别

6

我有一个简单的健康控制器定义如下:

@RestController
@RequestMapping("/admin")
public class AdminController {

    @Value("${spring.application.name}")
    String serviceName;

    @GetMapping("/health")
    String getHealth() {
        return serviceName + " up and running";
    }
}

以及用于测试它的测试类:

@WebMvcTest(RedisController.class)
class AdminControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void healthShouldReturnDefaultMessage() throws Exception {
        this.mockMvc.perform(get("/admin/health"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(content().string(containsString("live-data-service up and running")));
    }
}

运行测试时,我收到以下错误信息:

***************************
APPLICATION FAILED TO START
***************************

Description:

Field configuration in com.XXXX.LiveDataServiceApplication required a bean of type 'com.XXXXX.AppConfiguration' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'com.XXXX.AppConfiguration' in your configuration.

以下是与Spring Boot主应用程序类位于同一包中的AppConfiguration.java:

@Configuration
@EnableConfigurationProperties
@ConfigurationProperties
public class AppConfiguration {

    @Value("${redis.host}")
    private String redisHost;

    @Value("${redis.port}")
    private int redisPort;

    @Value("${redis.password:}")
    private String redisPassword;
...
// getters and setters come here

主类:

@SpringBootApplication
public class LiveDataServiceApplication {

    @Autowired
    private AppConfiguration configuration;

    public static void main(String[] args) {
        SpringApplication.run(LiveDataServiceApplication.class, args);
    }

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration(configuration.getRedisHost(), configuration.getRedisPort());
        redisConfiguration.setPassword(configuration.getRedisPassword());
        return new LettuceConnectionFactory(redisConfiguration);
    }
}

如果我将测试类中的注释修改为以下内容,则测试通过:

@SpringBootTest
@AutoConfigureMockMvc
class AdminControllerTest {
....

我错过了什么?


你正在LiveDataServiceApplication类中为AppConfiguration执行自动装配。但是你没有将AppConfiguration类标记为bean。 - Deepak Kumar
我不明白你的意思,你是指不将AppConfiguration类标记为bean吗? - belgoros
你需要使用任何注释类型,如@Service来为类AppConfiguration进行注释。 - Deepak Kumar
我已经使用@Configuration定义了它,这个注解别名是@Component。这不够吗? - belgoros
让我们在聊天中继续这个讨论 - belgoros
显示剩余2条评论
2个回答

7

了解如何使用@WebMvcTest@SpringBootTest

@WebMvcTest:注解仅实例化 Web 层而非整个上下文,因此控制器类中的所有依赖关系都应该被模拟。您可以查看文档

在具有多个控制器的应用程序中,您甚至可以使用例如@WebMvcTest(HomeController.class)只请求实例化一个控制器。

我们使用 @MockBean 创建并注入 GreetingService 的模拟对象(如果不这样做,应用程序上下文将无法启动)。

SpringBootTest: Spring boot 测试注解实际加载测试环境的应用程序上下文

@SpringBootTest 注解告诉 Spring Boot 查找主配置类(例如带有 @SpringBootApplication),并使用它来启动 Spring 应用程序上下文。


1
那么,为什么我的 AppConfiguration 类在我启动应用程序时被加载,但在运行测试时却没有被加载?我真的需要保留一个单独的配置类吗?一旦它被移除并且在 LiveDataServiceApplication 中替换了要读取的属性,它在测试中也能正常工作。 - belgoros
我认为如果将它们移动到单独的包中,它们可能无法正常工作,请阅读我的答案和附加文档@belgoros。 - Ryuzaki L
不,我没有移动任何东西,只是删除了AppConfiguration类。 - belgoros
如果您将其删除,代码将能够正常运行,因为它不需要将 AppConfiguration 注入主类。当使用 @WebMvcTest 时,它只会加载控制器,所有其他 bean 应该被模拟。 - Ryuzaki L
好的,有关于使用单独配置类的文档吗?或者我们可以在项目中任何地方使用“@Value”注解来声明所需的属性吗? - belgoros
显示剩余2条评论

0

在src/test/resource/application.file中定义所有属性

使用junit 5来测试rest层的示例:

@ExtendWith(MockitoExtension.class)
public class RestTest {

    
    @InjectMocks
    private RestClass  restClass;
    
    
    
    private MockMvc mockMvc;
    
    @BeforeEach
    public void init() throws Exception {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(restClass).build();
    }
    
    @Test
    public void test() throws Exception {
        String url = "/url";
        ResultActions resultActions = mockMvc.perform(get(url));
        resultActions.andExpect(status().isOk());

    }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接