【问题标题】:Spring Boot - Test for controller fails with 404 codeSpring Boot - 控制器测试失败并出现 404 代码
【发布时间】:2017-05-23 18:12:20
【问题描述】:

我想为控制器编写一个测试。这里是测试sn-p:

@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());
    }
}

控制器代码sn-p:

@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

我可以在这里找到问题所在。
如何修复控制器测试?

【问题讨论】:

  • 当我重命名包并忘记在@ComponentScan 中更改时遇到了类似的问题。

标签: spring unit-testing spring-boot controller


【解决方案1】:

基于accepted answer,在我的例子中,我已经根据另一个测试复制并修改了文件,但忘记在类的顶部更改控制器的名称,即如错误所述,它没有找到资源的原因。

@RunWith(SpringRunner.class)
@WebMvcTest(AnswerCommandController.class)
public class AnswerCommandControllerTest {

【讨论】:

    【解决方案2】:

    我遇到了同样的问题。尽管使用@WebMvcTest(MyController.class) 指定了控制器,但它没有被拾取。这意味着它的所有映射都被忽略了,导致了 404。添加 @Import(MyController.class) 解决了这个问题,但是当我已经指定要测试的控制器时,我没想到导入是必要的。

    【讨论】:

    • 这没有任何意义,但对我有用:D。我正在使用 Spring Boot 2.4.4
    【解决方案3】:

    就我而言,这是关于缺少起始斜线/

    我已将/ 附加到RequestMapping valueMockHttpServletRequestBuilder post urlTemplate 参数作为第一个字符。

    【讨论】:

      【解决方案4】:

      我通过@ContextConfiguration(classes = MyConfig.class)导入外部配置类

      当我将MyConfig 注释@Configuration 更改为@TestConfiguration 时,它开始正常工作。

      【讨论】:

        【解决方案5】:

        经过一些调试,似乎目标控制器根本没有注册为方法处理程序。 Spring 扫描 bean 是否存在 RestController 注释。

        但问题是,只有通过 CGLIB 代理 bean 才能找到注解,但对于我们使用 WebMvcTest 的情况,它是由 JDK 代理的.

        结果,我搜索了负责做出选择的配置,最终找到了AopAutoConfiguration。因此,当使用 SpringBootTest 时,当您在控制器中需要 WebMvcTest+PreAuthorize 时会自动加载这个,然后只需使用:

        @Import(AopAutoConfiguration.class)
        

        【讨论】:

        • 导入自动配置的正确方法是使用@ImportAutoConfiguration。或者,您可以使用@EnableAspectJAutoProxy
        【解决方案6】:

        我找不到好的答案,但我可以找到原因之一。

        我在测试中使用了 RestController 上的 @PreAuthorize
        您可以在使用 SpringBootTest 的集成测试中使用 this tip 模拟 Oauth。对于SpringBootTest,这也很有效,但是使用SpringBootTest 会加载很多其他资源(如JPA),而这些资源对于进行简单的控制器测试是不必要的。

        但是对于@WebMvcTest,这不会按预期工作。使用WithMockOAuth2Scope注解足以阻止401错误从认证问题,但之后WebMvcTest找不到其余端点,返回404错误代码。

        删除Controller上的@PreAuthorize后,WebMvcTest的测试通过。

        【讨论】:

          【解决方案7】:

          HTTP code 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") 
          

          顺便说一句,您不必在MockConfig 类中手动设置WeatherStationService,Spring boot 可以为您注入一个模拟并在每个测试方法后自动重置它,您只需在测试类中声明它即可:

          @MockBean
          private IStationRepository stationRepository;
          

          另一方面,你应该在你的测试方法中调用get("/stations")之前模拟weatherService.getAllStations()(因为你没有运行integration test),所以你可以这样做:

          List<WeatherStation> myList = ...;
          //Add element(s) to your list
           Mockito.when(stationService.getAllStations()).thenReturn(myList);
          

          您可以在以下位置找到更多信息:

          【讨论】:

          • 对我来说,结果就像在请求路径的开头缺少“/”一样简单。我在控制器测试中尝试使用“v1/user/{id}”而不是“/v1/user/{id}”。
          【解决方案8】:

          这是一种适用于我的控制器测试的不同方法。

          假设: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 类。

          【讨论】:

          • 希望这次的建议对你有所帮助,现在还为时不晚。
          【解决方案9】:

          我不确定为什么您的测试不起作用。但我得到了另一个适合我的解决方案。

          @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());
              }
          }
          

          【讨论】:

          • 您如何看待完整的控制器测试?
          • @nazar_art 我克隆了你的 github 项目,但它充满了错误。不确定您的 MockMvc 是否正确。我会像我提供的那样简单地在您的测试类中注册一个控制器。
          • 这个应用只有一个控制器。此外,您需要为您的 IDE 设置 lombok 支持。没有这个,它就无法编译。
          • 对于 IntelliJ,您只需在整个项目的设置中安装 Lombok pluginenable annotation processor
          猜你喜欢
          • 2018-08-15
          • 1970-01-01
          • 2020-06-15
          • 2019-02-20
          • 2016-09-17
          • 2018-02-20
          • 1970-01-01
          • 1970-01-01
          • 2018-01-02
          相关资源
          最近更新 更多