Spring Boot - 控制器测试失败,带有404代码

时间:2017-01-09 13:06:04

标签: spring unit-testing spring-boot controller

我想为控制器编写一个测试。这是测试片段:

@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

我可以在这里弄错。
如何修复控制器测试?

9 个答案:

答案 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代理的。

strong>。

结果,我搜索了负责选择的配置,最后找到了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 {