如何告诉 spring 只加载 JUnit 测试所需的 bean?

How to tell spring to only load the needed beans for the JUnit test?

一个可能有高级答案的简单问题。

问题: 我的问题是,有没有办法在您的应用程序上下文中仅实例化特定 JUnit 测试所需的 classes?

原因: 我的应用程序上下文变得相当大。我也做了很多集成测试,所以我想你会理解我说每次我 运行 测试时我的应用程序上下文中的所有 classes 都会被实例化,这需要时间。

示例:

说 class Foo 只注入 bar

public class Foo {

@Inject
Bar bar;

@Test
public void testrunSomeMethod() throws RegisterFault {
    bar.runSomeMethod();
}

但是应用程序上下文有 bean foobar 和 bar。我知道这不是一个有效的应用程序上下文,但请放心,我的所有代码都能正常工作。

<beans>
     <bean id="foobar" class="some.package.FooBar"/>
     <bean id="bar" class="some.package.Bar"/>
<beans>

那么我如何告诉 spring 只实例化 Bar 而忽略 FooBar 进行测试 class foo.

谢谢。

是的,我们可以做到这一点,每个测试用例使用上下文。使用测试用例所需的 bean 准备一个测试上下文 xml 文件。

如果你使用maven,将test-context.xml放在src/test/resources文件夹下。

用下面的注释

注释你需要的测试class

@ContextConfiguration(locations = "classpath:test-application-context.xml")

这有助于仅为测试用例加载特定的 bean。

如果你有两种测试用例,那么

@Runwith(SpringJUnit4Runner.class)
@ContextConfiguration(locations = "classpath:test-context-case1.xml")
public class TestClassCase1 {}

@Runwith(SpringJUnit4Runner.class)
@ContextConfiguration(locations = "classpath:test-context-case2.xml")
public class TestClassCase2 {}

这不是直接的答案,所以我不会将其标记为解决方案。但希望对您有所帮助。

一般我看到三个选项。

  1. VinayVeluri 回答得很好。创建单独的上下文并在每个测试中分别启动它们。

  2. 为所有测试创建一次上下文。就像这里:Reuse spring application context across junit test classes这是一次测试所有测试的大优化。

  3. 混合前两点。仅出于测试目的创建一个较小的上下文。模拟一下,从未测试过但可以抛出 NPE 等。像这里一样:Injecting Mockito mocks into a Spring bean 以促进上下文构建。并像第 2 点一样重复使用它。一次性构建所有测试。我个人会选择那个。

  4. 这个等待关于某种智能测试运行器的答案,它为每个测试创建最少需要的上下文。

考虑将 default-lazy-init="true" 添加到您的 spring 上下文 xml bean 标记(或将 lazy-init="true" 添加到那些需要很长时间启动的特定 bean)。 这将确保只创建那些使用 applicationContext.getBean(class-or-bean-name) 调用或通过 @Autowired / @Inject 注入到测试中的 bean。 (仍然会创建一些其他类型的 bean,例如 @Scheduled bean,但您需要检查这是否是一个问题)

(如果你使用spring Java配置,在配置文件中添加@Lazy

警告 - 如果有一个 bean 没有使用 applicationContext.getBean() 显式初始化或作为使用 [=25 获得的 bean 使用的依赖项注入=](),那么将不再构造或初始化该 bean。根据您的应用程序,这可能会导致事情失败或不会。也许您可以有选择地将这些 bean 标记为 lazy-init="false"