英文:
Spring Boot @WebMvcTest vs @SpringBootTest
问题
我有一个简单的健康控制器定义如下:
@RestController
@RequestMapping("/admin")
public class AdminController {
@Value("${spring.application.name}")
String serviceName;
@GetMapping("/health")
String getHealth() {
return serviceName + " up and running";
}
}
以及用于测试的测试类:
@WebMvcTest(AdminController.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 {
...
我漏掉了什么?
英文:
I have a simple health controller defined as follows:
@RestController
@RequestMapping("/admin")
public class AdminController {
@Value("${spring.application.name}")
String serviceName;
@GetMapping("/health")
String getHealth() {
return serviceName + " up and running";
}
}
And the test class to test it:
@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")));
}
}
When running the test, I'm getting the below error:
***************************
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.
Here is AppConfiguration.java
defined in the same package as the main spring boot app class:
@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
Main class:
@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);
}
}
If I modify the annotation in the test class as follows, the test pass:
@SpringBootTest
@AutoConfigureMockMvc
class AdminControllerTest {
....
What am I missing?
答案1
得分: 7
你应该理解 @WebMvcTest
和 @SpringBootTest
的用法。
@WebMvcTest: 这个注解只会实例化Web层,而不是整个上下文,所以控制器类中的所有依赖都应该被模拟。你可以查看文档。
>Spring Boot 只会实例化Web层,而不是整个上下文。在一个包含多个控制器的应用中,你甚至可以通过使用 @WebMvcTest(HomeController.class)
来只实例化其中一个。
>我们使用 @MockBean
来创建并注入 GreetingService 的模拟(如果不这样做,应用程序上下文将无法启动)。
@SpringBootTest: SpringBootTest
注解实际上会加载用于测试环境的应用程序上下文。
>@SpringBootTest
注解告诉 Spring Boot 查找一个主要的配置类(比如带有 @SpringBootApplication
的类),并使用它来启动一个 Spring 应用程序上下文。
英文:
You should understand the usage of @WebMvcTest
and @SpringBootTest
@WebMvcTest : annotation is only to instantiates only the web layer rather than the whole context, so all dependencies in controller class should be mocked, you can look at the documentation
>Spring Boot instantiates only the web layer rather than the whole context. In an application with multiple controllers, you can even ask for only one to be instantiated by using, for example, @WebMvcTest(HomeController.class).
>We use @MockBean to create and inject a mock for the GreetingService (if you do not do so, the application context cannot start)
SpringBootTest : Spring boot test annotation actual load the application context for test environment
>The @SpringBootTest annotation tells Spring Boot to look for a main configuration class (one with @SpringBootApplication, for instance) and use that to start a Spring application context.
答案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());
}
}
英文:
Define all properties in src/test/resource/application.file
example to use junit 5 for rest layer:
@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());
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论