我想为控制器编写一个测试。这是测试片段:
@RunWith(SpringRunner.class)
@WebMvcTest(WeatherStationController.class)
@ContextConfiguration(classes = MockConfig.class)
public class WeatherStationControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private IStationRepository stationRepository;
@Test
public void shouldReturnCorrectStation() throws Exception {
mockMvc.perform(get("/stations")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
控制器代码片段:
@RestController
@RequestMapping(value = "stations")
public class WeatherStationController {
@Autowired
private WeatherStationService weatherService;
@RequestMapping(method = RequestMethod.GET)
public List<WeatherStation> getAllWeatherStations() {
return weatherService.getAllStations();
}
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public WeatherStation getWeatherStation(@PathVariable String id) {
return weatherService.getStation(id);
}
MockConfig 类:
@Configuration
@ComponentScan(basePackages = "edu.lelyak.repository")
public class MockConfig {
//**************************** MOCK BEANS ******************************
@Bean
@Primary
public WeatherStationService weatherServiceMock() {
WeatherStationService mock = Mockito.mock(WeatherStationService.class);
return mock;
}
这是错误堆栈跟踪:
java.lang.AssertionError: Status
Expected :200
Actual :404
我可以明白这里出了什么问题。
如何修复控制器测试?
我也有同样的问题。尽管用
@WebMvcTest(MyController.class)
指定了控制器,但控制器并未被拾取。这意味着它的所有映射都被忽略,导致 404。添加 @Import(MyController.class)
解决了问题,但我没想到当我已经指定要测试哪个控制器时需要导入。
HTTP代码404,意味着(在服务器上)找不到您的请求的资源,我认为您的控制器在Spring Boot中不可见(让我说没有扫描)。
一个简单的解决方案是扫描
MockConfig
类中的父包,这样Spring就可以拾取所有bean,
@ComponentScan(basePackages = "edu.lelyak") // assuming that's the parent package in your project
如果你不喜欢这种方式,你可以在
basePackages
中添加控制器的包名
@ComponentScan(basePackages = {"edu.lelyak.controller","edu.lelyak.repository")
顺便说一句,你不必在
WeatherStationService
类中手动设置 MockConfig
,Spring boot 可以为你注入一个模拟并在每个测试方法后自动重置它,你应该在你的测试类中声明它:
@MockBean
private IStationRepository stationRepository;
另一方面,您应该在测试方法中调用
weatherService.getAllStations()
之前模拟get("/stations")
(因为您没有运行集成测试),所以您可以这样做:
List<WeatherStation> myList = ...;
//Add element(s) to your list
Mockito.when(stationService.getAllStations()).thenReturn(myList);
您可以在以下位置找到更多信息:
经过一些调试,目标控制器似乎根本没有注册为方法处理程序。 Spring 扫描 bean 是否存在
RestController
注释。
但是问题是,只有当bean通过CGLIB代理时才能找到注释,但是对于我们使用
WebMvcTest
的情况,它是由JDK代理的。
结果我去寻找负责做出选择的配置,终于找到了
AopAutoConfiguration
。因此,当使用 SpringBootTest 时,当您在控制器中需要 WebMvcTest+PreAuthorize
时,会自动加载此测试,然后只需使用:
@Import(AopAutoConfiguration.class)
我不确定为什么你的测试不起作用。但我得到了另一个适合我的解决方案。
@SpringBootTest
public class ControllerTest {
@Autowired
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();
}
@Test
public void shouldReturnCorrectStation() throws Exception {
mockMvc.perform(get("/stations")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
我通过
@ContextConfiguration(classes = MyConfig.class)
导入外部配置类
当我将
MyConfig
注释 @Configuration
更改为 @TestConfiguration
时,它开始正常工作。
我找不到好的答案,但我可以找到原因之一。
我在测试中使用了 RestController 上的
@PreAuthorize
。SpringBootTest
的集成测试中使用 thistip来模拟 Oauth。对于
SpringBootTest
,这也非常有效,但是使用 SpringBootTest
您会加载许多其他资源(例如 JPA),而这些资源对于进行简单的控制器测试来说是不必要的。
但是对于
@WebMvcTest
,这不会按预期工作。使用 WithMockOAuth2Scope 注释足以阻止身份验证问题导致的 401 错误,但之后 WebMvcTest 找不到其余端点,返回 404 错误代码。
移除控制器上的
@PreAuthorize
后,WebMvcTest
测试通过。
基于接受的答案,在我的例子中,我根据另一个测试复制并修改了文件,但忘记了更改类顶部控制器的名称,这就是它不存在的原因找到资源,如错误所示。
@RunWith(SpringRunner.class)
@WebMvcTest(AnswerCommandController.class)
public class AnswerCommandControllerTest {
这是对我有用的控制器测试的不同方法。
假设:类
WeatherStationService
是一个@SpringBootApplication
那么,下面的测试类应该适合您:
@RunWith(SpringRunner.class)
@SpringApplicationConfiguration(WeatherStationService.class)
@WebIntegrationTest
public class WeatherStationControllerTest {
@Autowired
private WebApplicationContext context;
MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
@Test
public void shouldReturnCorrectStation() throws Exception {
mockMvc.perform(get("/stations")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk();
}
}
通过此测试设置,您应该不再需要
MockConfig
类。
就我而言,这是关于缺少起始斜杠
/
我已将
/
附加到 RequestMapping value
和 MockHttpServletRequestBuilder post urlTemplate
参数作为第一个字符。
以防有人想知道。
如果我们不使用
@ContextConfiguration
,@WebMvcTest
注释将加载REST控制器类。否则,当我们使用 use @ContextConfiguration
时,似乎 ContextConfiguration
会清除上下文 REST 控制器配置。我们需要将 REST 控制器添加到 ContextConfiguration
,例如:
@ContextConfiguration(classes = {MockConfig.class, WeatherStationController.class})
就我而言,我还必须将控制器添加到@ContextConfiguration。
@ContextConfiguration(classes = {MockConfig.class, WeatherStationController.class})
看着这个答案,我认为问题可能在于使用
ContextConfiguration
创建正确的上下文。WebMvcTest
的 documentations中,它说:
通常 @WebMvcTest 与 @MockBean 或 @Import 结合使用来创建 @Controller beans 所需的任何协作者。
所以我用
ContextConfiguration
替换了 Import
并且成功了。