JUnit 测试时加载 ApplicationContext 失败

1、概览

Spring Boot 应用中,可以同时包含基于注解和基于 XML 的配置来混合定义 Bean。在这种环境中,如果你在测试类中使用基于 XML 的配置可能会遇到 “Failed to load ApplicationContext” 异常。因为 Application Context 没有加载到 Test Context 中。

本文将会带你了解如何把 XML Application Context 集成到 Spring Boot 应用的测试中。

2、“Failed to load ApplicationContext” 异常

在 Spring Boot 应用中集成基于 XML 的 Application Context 来重现该异常。

首先,假设有一个包含 Service Bean 定义的 application-context.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="employeeServiceImpl" class="com.baeldung.xmlapplicationcontext.service.EmployeeServiceImpl" />
</beans>

webapp/WEB-INF/ 位置添加 application-context.xml 文件:

webapp/WEB-INF/ 目录结构

再创建一个 Service 接口和实现类:

public interface EmployeeService {
    Employee getEmployee();
}

public class EmployeeServiceImpl implements EmployeeService {

    @Override
    public Employee getEmployee() {
        return new Employee("Baeldung", "Admin");
    }
}

最后,创建一个测试用例,用于从 Application Context 中获取 EmployeeService Bean:

@RunWith(SpringRunner.class)
@ContextConfiguration(locations={"classpath:WEB-INF/application-context.xml"})
public class EmployeeServiceAppContextIntegrationTest {

    @Autowired
    private EmployeeService service;

    @Test
    public void whenContextLoads_thenServiceISNotNull() {
        assertThat(service).isNotNull();
    }

}

现在,如果尝试运行这个测试,就会遇到异常:

java.lang.IllegalStateException: Failed to load ApplicationContext

出现这个异常,是因为 Application Context 没有加载到 Test Context 中。此外,根本原因是 classpath 中未包含 WEB-INF

@ContextConfiguration(locations={"classpath:WEB-INF/application-context.xml"})

3、在测试中使用基于 XML 的 ApplicationContext

在测试中使用基于 XML 的 ApplicationContext 时,有两种选择: @SpringBootTest@ContextConfiguration 注解。

3.1、测试使用 @SpringBootTest@ImportResource

Spring Boot 提供了 @SpringBootTest 注解,可以用它来创建 Application Context,以便在测试中使用。此外,还必须在 Spring Boot main 类中使用 @ImportResource 来读取 XML Bean。该注解允许导入一个或多个包含 Bean 定义的资源。

在 main 类中使用 @ImportResource 注解导入 xml 配置:

@SpringBootApplication
@ImportResource({"classpath*:application-context.xml"})

现在,创建测试用例,从 Application Context 中获取 EmployeeService Bean:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = XmlBeanApplication.class)
public class EmployeeServiceAppContextIntegrationTest {

    @Autowired
    private EmployeeService service;

    @Test
    public void whenContextLoads_thenServiceISNotNull() {
        assertThat(service).isNotNull();
    }

}

@ImportResource 注解会加载 resource 目录中的 XML Bean。@SpringBootTest 注解会在测试类中加载整个应用的 Bean。因此,可以在测试类中访问 EmployeeService Bean。

3.2、使用 @ContextConfigurationresources 进行测试

可以将测试配置文件放在 src/test/resources 目录中,创建具有不同 Bean 配置的 Test Context。

在本例中,使用 @ContextConfiguration 注解从 src/test/resources 目录加载 Test Context。

首先,实现 EmployeeService 接口创建另一个 Bean:

public class EmployeeServiceTestImpl implements EmployeeService {

    @Override
    public Employee getEmployee() {
        return new Employee("Baeldung-Test", "Admin");
    }
}

然后,在 src/test/resources 目录中创建 test-context.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="employeeServiceTestImpl" class="process.service.EmployeeServiceTestImpl" />
</beans>

最后,创建测试用例:

@SpringBootTest
@ContextConfiguration(locations = "/test-context.xml")
public class EmployeeServiceTestContextIntegrationTest {

    @Autowired
    @Qualifier("employeeServiceTestImpl")
    private EmployeeService serviceTest;

    @Test
    public void whenTestContextLoads_thenServiceTestISNotNull() {
        assertThat(serviceTest).isNotNull();
    }

}

如上,使用 @ContextConfiguration 注解从 test-context.xml 中加载了 employeeServiceTestImpl

3.3、使用 @ContextConfigurationWEB-INF 进行测试

还可以在测试类中使用 file URL 从 WEB-INF 目录导入 Application Context。

@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/application-context.xml")

4、总结

本文介绍了如何在 Spring Boot 应用的测试中使用基于 XML 的配置文件。


参考:https://www.baeldung.com/spring-junit-failed-to-load-applicationcontext