Springs MockMvc 以两种稍微不同的方法之一返回空内容

Sha*_*ady 6 java rest spring spring-mvc mockmvc

我正在测试一个 Spring MVC @RestController,它反过来调用外部 REST 服务。我MockMvc用来模拟 spring 环境,但我希望我的控制器能够真正调用外部服务。手动测试 RestController 工作正常(使用 Postman 等)。

我发现如果我以特定方式设置测试,我会得到一个完全空的响应(状态代码除外):

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = AnywhereController.class)
public class AnywhereControllerTest{

    @Autowired
    private AnywhereController ac;

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }

    @Test
    public void testGetLocations() throws Exception {

        ...

        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/anywhere/locations").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(containsString("locations")))
                .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON));
        .andReturn();
    } 
Run Code Online (Sandbox Code Playgroud)

测试失败,因为内容和标题为空。然后我尝试将其添加到测试类中:

@Configuration
@EnableWebMvc
public static class TestConfiguration{
    @Bean
    public AnywhereController anywhereController(){
        return new AnywhereController();
    }
}
Run Code Online (Sandbox Code Playgroud)

另外我更改了ContextConfiguration注释(尽管我想知道这实际上是做什么的):

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class AnywhereControllerTest{...}
Run Code Online (Sandbox Code Playgroud)

现在突然所有检查都成功了,在打印内容正文时,我得到了所有内容。

这里发生了什么?这两种方法有什么区别?

Sha*_*ady 3

评论中有人提到了@EnableWebMvc,事实证明这是正确的线索。我没有使用@EnableWebMvc,因此

如果您不使用此注释,您最初可能不会注意到任何差异,但是诸如内容类型和接受标头之类的内容,通常内容协商将不起作用。来源

我对框架内部工作原理的了解有限,但启动过程中的一个简单警告可能会节省许多时间的调试时间。当人们使用 @Configuration 和/或 @RestController 时,他们很可能也想使用 @EnableWebMvc (或其 xml 版本)。

更糟糕的是,Spring Boot 自动添加了这个注释,这就是为什么互联网上的许多教程(也是官方的)都没有提到@EnableWebMvc。