【问题标题】:How to tell spring to only load the needed beans for the JUnit test?如何告诉spring只加载JUnit测试所需的bean?
【发布时间】:2023-04-07 05:35:01
【问题描述】:

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

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

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

例子:

说类 Foo 只注入吧

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 而忽略测试类 foo 的 FooBar。

谢谢。

【问题讨论】:

  • 您是否尝试过为所有测试创建一次上下文?或者它不是一个选择? stackoverflow.com/questions/8501975/…
  • 我已经考虑过了,但是我有很多测试,因此为每个测试创建应用程序上下文需要时间。我希望从所说的应用程序上下文中告诉 spring 我需要什么
  • 我认为我们有误会。我的意思是,创造一次。因此,您不必为每个测试创建上下文。您创建上下文,然后在此创建的上下文上启动测试。如果这不是选项,因为您正在对 bean 进行一些更改,并且您需要重置它们,那么 VinayVeluri 的答案很好。但是你需要创建单独的 xml 文件,这可能有点烦人,你有 100 个上下文文件。如果您想为每个测试提供单独的上下文 o0 或混合解决方案 ;)
  • 哦,好的,我明白你对这个问题的回答。我认为它和Vinay Veluri一样。看到这个解决方案的问题是。如果您同时运行所有测试,效果很好,这实际上是我忙于测试的方式,但如果您只想多次运行一个测试(比如说您正忙于测试代码,某些东西不起作用,您进行更改然后测试再次)这需要时间。我正在努力消除它所花费的时间
  • 两个解决方案同时,我猜会解决你的问题:P 但你不能合并它们。因此,在进行完整测试时,创建一次,但在单独测试时 - 创建所需的最少上下文。我不知道它是否可能,就像智能​​测试运行器一样,会知道它应该创建什么上下文。或者也许改变你的测试方法?恕我直言,集成测试应该一次运行。就像詹金斯一样。因为他们离他们的定义很远。一个一个地运行,应该是干净的单元测试。单元测试不到第二次。所以我会去模拟 - Mockito。一如既往。但那是离题的。

标签: java spring junit applicationcontext


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    使用以下注释注释您所需的测试类

    @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 {}
    

    【讨论】:

    • 我已经考虑过了,但是我有很多测试,因此为每个测试创建应用程序上下文需要时间。我希望从所说的应用程序上下文中告诉 spring 我需要什么
    • 是否有任何基于注释的方法?
    • 嗨,如何编写test-context-case1.xml 以自动包含某些包中的所有文件(例如 com.company.project.module_one)?我知道如何使用@ComponentScan 来做到这一点,但似乎这在这里不起作用......谢谢!
    【解决方案3】:

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

    通常我看到三个选项。

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

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

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

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

    【讨论】:

    • 广告。 4:你不能真正自动地做到这一点。 bean 在创建时可能会运行一些代码,并且无法自动确定此代码是否重要。虽然这将是糟糕的编码,但您可以拥有一个 bean,它在创建时将一些记录添加到数据库中,然后部分代码稍后会读取该记录。作为开发人员,您可能能够发现此类依赖关系,但您无法自动完成 - 这将等同于停机问题或更糟。
    • 广告。 4:虽然测试并不总能判断应用程序是否“正确”,但可以自动生成“建议的最小上下文”并尝试运行测试。只要测试通过,上下文就是正确的。看看“变异”测试,它可以发现,如果你的测试实际上是在测试什么,什么可以被破坏......例如见pitest.org
    猜你喜欢
    • 1970-01-01
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    • 1970-01-01
    • 2019-01-30
    • 1970-01-01
    • 2020-01-17
    相关资源
    最近更新 更多