我想为控制器编写一个测试。这是测试片段:
@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
我可以在这里弄错。
如何修复控制器测试?
答案 0 :(得分:5)
我不确定为什么你的测试不起作用。但我得到了另一个适合我的解决方案。
response = dict(Person.objects.annotate(count=Count('city')).\
values_list('city', 'count'))
答案 1 :(得分:5)
我有同样的问题。尽管使用@WebMvcTest(MyController.class)
指定了控制器,但仍未将其拿起。这意味着所有的映射都将被忽略,从而导致404。添加@Import(MyController.class)
解决了该问题,但是当我已经指定要测试的控制器时,我并不认为导入是必需的。
答案 2 :(得分:4)
HTTP code 404,表示没有找到(在服务器上)您的请求的资源,我认为您的控制器在弹簧启动时不可见(让我说不扫描)。
一个简单的解决方案是在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启动可以为你注入一个模拟并在每个测试方法后自动重置它,你应该声明它在你的测试类中:
@MockBean
private IStationRepository stationRepository;
另一方面,你应该在测试方法中调用weatherService.getAllStations()
之前模拟get("/stations")
(因为你没有运行integration test),所以你可以这样做:
List<WeatherStation> myList = ...;
//Add element(s) to your list
Mockito.when(stationService.getAllStations()).thenReturn(myList);
您可以在以下网址找到更多信息:
答案 3 :(得分:1)
以下是对我有用的控制器测试的不同方法。
假设:课程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
类。
答案 4 :(得分:1)
我找不到一个好的答案但我能找到其中一个原因。
我在我的测试中使用了RestController上的@PreAuthorize
您可以在使用SpringBootTest
的集成测试中使用this tip模拟Oauth。对于SpringBootTest
,这也很有效,但使用SpringBootTest
加载了许多其他资源(如JPA),这些资源不是进行简单的Controller测试所必需的。
但是@WebMvcTest
这不能按预期工作。使用WithMockOAuth2Scope注释足以阻止401错误导致身份验证问题,但之后WebMvcTest无法找到其余端点,返回404错误代码。
删除Controller上的@PreAuthorize
后,WebMvcTest
的测试通过。
答案 5 :(得分:1)
在进行一些调试之后,似乎没有将目标控制器注册为方法处理程序。 Spring扫描Beans是否存在RestController
批注。
但是问题是,只有通过 CGLIB 代理该bean才能找到注释,但是对于我们使用WebMvcTest
的情况,它是通过 JDK代理的。
结果,我搜索了负责选择的配置,最后找到了AopAutoConfiguration
。因此,当使用SpringBootTest时,当您在控制器中需要WebMvcTest+PreAuthorize
时会自动加载该代码,然后只需使用:
@Import(AopAutoConfiguration.class)
答案 6 :(得分:0)
我通过"selectAction": {
"type": "Action.Submit",
"id": "0",
"title": "action0",
"data": {
"DataParam": " DataValue"
}
}
导入外部配置类
当我将@ContextConfiguration(classes = MyConfig.class)
注释MyConfig
更改为@Configuration
时,它开始正常工作。
答案 7 :(得分:0)
就我而言,这是因为缺少一个起始斜杠/
我已将/
和RequestMapping value
参数都附加到第一个字符。
答案 8 :(得分:0)
基于 accepted answer,在我的情况下,我根据另一个测试复制并修改了文件,但忘记在类的顶部更改控制器的名称,即这是它没有像错误所说的那样找到资源的原因。
@RunWith(SpringRunner.class)
@WebMvcTest(AnswerCommandController.class)
public class AnswerCommandControllerTest {