1. 概述

在这篇文章中,我们将探讨Spring框架中的@WebAppConfiguration注解,了解它在集成测试中的作用以及如何配置它,以便在测试中启动一个WebApplicationContext

2. @WebAppConfiguration

简单来说,这是一个类级别的注解,用于在Spring框架中创建应用程序上下文的Web版本。

它用于表示为测试启动的ApplicationContext应该是一个WebApplicationContext实例。

关于使用方法的小提示:我们通常会在集成测试中找到这个注解,因为WebApplicationContext用于构建MockMvc对象。有关Spring集成测试的更多信息,请参阅这里

3. 加载WebApplicationContext

从Spring 3.2开始,现在支持在集成测试中加载WebApplicationContext

@WebAppConfiguration
@ContextConfiguration(classes = WebConfig.class)
public class EmployeeControllerTest {
    ...
}

这指示TestContext框架为测试加载一个WebApplicationContext

在后台,TestContext框架会创建一个MockServletContext并将其提供给我们的测试的WebApplicationContext

3.1. 配置选项

默认情况下,WebApplicationContext的基础资源路径将设置为"file:src/main/webapp",这是Maven项目中WAR根目录的默认位置。

但是,我们可以通过向@WebAppConfiguration注解提供替代路径来覆盖它:

@WebAppConfiguration("src/test/webapp")

我们也可以从类路径而不是文件系统引用基础资源路径:

@WebAppConfiguration("classpath:test-web-resources")

3.2. 缓存

一旦WebApplicationContext加载完成,它将被缓存并在同一测试套件中声明具有相同独特上下文配置的所有后续测试中重复使用。

有关缓存的更多详细信息,请参阅参考手册中的上下文缓存部分。

4. 在测试中使用@WebAppConfiguration

现在我们理解了为什么要在测试类中添加@WebAppConfiguration注解,让我们来看看如果我们忘记添加它时会发生什么,当我们使用WebApplicationContext时。

@RunWith(SpringJUnit4ClassRunner.class)
// @WebAppConfiguration omitted on purpose
@ContextConfiguration(classes = WebConfig.class)
public class EmployeeTest {

    @Autowired
    private WebApplicationContext webAppContext;
    private MockMvc mockMvc;

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

请注意,我们已注释掉注解以模拟忘记添加的情况。运行JUnit测试时很容易看到问题:**我们在没有设置的情况下尝试在类中自动装配WebApplicationContext**。

然而,更典型的例子是使用Spring Web配置的测试;实际上,这就足以使测试失败。

让我们看看:

@RunWith(SpringJUnit4ClassRunner.class)
// @WebAppConfiguration omitted on purpose
@ContextConfiguration(classes = WebConfig.class)
public class EmployeeTestWithoutMockMvc {

    @Autowired
    private EmployeeController employeeController;

    ...
}

尽管上述示例并未自动装配WebApplicationContext,但它仍然会失败,因为它试图使用一个Web启用的配置——WebConfig

@Configuration
@EnableWebMvc
@ComponentScan("com.baeldung.web")
public class WebConfig implements WebMvcConfigurer {
    ...
}

罪魁祸首是@EnableWebMvc注解——它基本上需要一个Web启用的Spring上下文,如果没有它,我们将看到测试失败:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
  No qualifying bean of type [javax.servlet.ServletContext] found for dependency: 
    expected at least 1 bean which qualifies as autowire candidate for this dependency. 

Dependency annotations: 
  {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at o.s.b.f.s.DefaultListableBeanFactory
      .raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
    at o.s.b.f.s.DefaultListableBeanFactory
      .doResolveDependency(DefaultListableBeanFactory.java:1119)
    at o.s.b.f.s.DefaultListableBeanFactory
      .resolveDependency(DefaultListableBeanFactory.java:1014)
    at o.s.b.f.a.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement
      .inject(AutowiredAnnotationBeanPostProcessor.java:545)
    ... 43 more

这就是我们通过在测试中添加@WebAppConfiguration注解轻松解决的问题。

5. 总结

在这篇文章中,我们展示了如何让TestContext框架仅通过添加注解就能将WebApplicationContext加载到我们的集成测试中。

最后,我们探讨了即使添加了@ContextConfiguration到测试中,如果没有@WebAppConfiguration,这些测试也将无法正常工作的情况。

本文中的示例实现可以在我们的GitHub存储库这里中找到。