【问题标题】:Junit Spring avoid to load twice application context datasourceJunit Spring 避免加载两次应用程序上下文数据源
【发布时间】:2023-03-30 10:42:02
【问题描述】:

我有这个配置类:

@ComponentScan(
        basePackages = { 
                "mypackage.controller",
                "mypackage.service",
                "mypackage.repository" 
        }
)
@TestPropertySource(locations="classpath:configuration.properties")
@Import({
    H2Configuration.class
})
public class TestConfiguration {
}

@Configuration
public class H2Configuration {

    @Bean
    public DataSource dataSource() throws SQLException {
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        EmbeddedDatabase db = builder
                .setType(EmbeddedDatabaseType.H2)
                .addScript("h2/create.sql")
                .addScript("h2/insert.sql")
                .build();
        db.getConnection().setAutoCommit(false);
        return db;
    }

}

我有这两个类测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes = { TestConfiguration.class })
public class FirstRepositoryTest {

    @Autowired
    MyFirstRepositoryImpl repository;

    @Before
    public void initTest() {
    }

    @Test(expected = NullPointerException.class)
    public void testNullRecords() {
        repository.foo(null, null);
    }
}


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes = { TestConfiguration.class })
public class SecondRepositoryTest {

    @Autowired
    MySecondRepositoryImpl repository;

    @Before
    public void initTest() {
    }

    @Test(expected = NullPointerException.class)
    public void testSomethingNullRecords() {
        repository.something(null, null);
    }
}

如果我为每个类运行一次 junit 测试,一切顺利。

在全新安装阶段测试失败,因为应用程序上下文被初始化了两次。

例如,它尝试创建两次 h2 表并执行两次 insert.sql 脚本。

我必须做些什么来初始化 h2 数据库和应用程序上下文一次?

谢谢

【问题讨论】:

  • NB db.getConnection().setAutoCommit(false); 很浪费(因为它从数据源获取单个连接并将该连接上的自动提交设置为 false)并泄漏连接(返回的连接是可能来自池支持的源)。你应该删除那行代码。

标签: java spring applicationcontext


【解决方案1】:

我认为您可以开始查看有关 Integration Testing 的 Spring 文档。

将事务测试用于集成测试 (@Transactional) 也是一种很好的做法,它会在每个测试结束时回滚:请参阅 Transaction Management

为避免为每个测试类重新创建ApplicationContext 的成本,缓存可按此处的说明使用:Context Caching

对于嵌入式数据库的集成测试,您还可以找到文档:Testing Data Access Logic with an Embedded Database。 上一个链接中的注释,与您的用例匹配:

但是,如果您希望创建一个共享的嵌入式数据库 在测试套件中,考虑使用 Spring TestContext Framework 并在 Spring 中将嵌入式数据库配置为 bean ApplicationContext 如创建嵌入式数据库中所述 使用 Spring XML 并以编程方式创建嵌入式数据库。

希望你能找到一些有用的参考资料。

【讨论】:

  • 因此您可以在 @After@AfterClass 中调用 EmbeddedDatabase.shutdown(),就像 Spring 文档中的示例一样(使用嵌入式数据库测试数据访问逻辑) .
  • 我在内存数据库中使用单元测试,所以没有必要回滚。
  • 事实上,测试后回滚的目的是在集成测试之间提供清晰的隔离。它还避免了在测试后进行清洁。
【解决方案2】:

我从Embedded Database SupportSpring Boot 文档中找到的另一个好技巧:

他们说:

如果您在测试中使用此功能,您可能会注意到 整个测试套件都重用相同的数据库 您使用的应用程序上下文的数量。如果你想确定 每个上下文都有一个单独的嵌入式数据库,您应该设置 spring.datasource.generate-unique-name 为 true。

因此,要使每个 EmbeddedDatabase 独一无二,您可以尝试使用以下方法创建它们:

EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
                      .generateUniqueName(true)
                      ...
                      .build();

【讨论】:

  • 这是一个有趣的选择,也可以解决这个问题 - 感谢您的发帖!
【解决方案3】:

在单元测试中,您必须保证每个测试都是可重复的,并且与上下文无关。因此,仅加载一次上下文并不是一个好主意。最好在执行后重置。为此,您可以在测试类中使用 @DirtiesContext(classMode = ClassMode.AFTER_CLASS)

因此,当启动下一个 junit 类时,您将强制您的上下文重新启动

【讨论】:

  • 应用上下文是独立的,但内存中的数据库是一样的
  • 根据你的 Spring 上下文的复杂性,这将完全影响单元测试的性能。在我们的例子中,完全初始化 Spring 上下文需要 30 秒,这使得 DirtiesContext 完全无法接受。
【解决方案4】:

因此,失败的原因是当您在清理/安装过程中运行测试时,数据库 (H2) 驻留在内存中。创建/插入脚本在第一次测试运行后已经执行。在此之后的任何后续测试执行都将导致重新执行相同的脚本并且会发生错误。

使用DROP TABLE IF EXISTS <table name>; 更新您的创建脚本。这将确保表被删除然后重新创建。

注意:我不确定您为什么明确指定 AnnotationConfigContextLoader。我认为,没有它,跑步者SpringJUnit4ClassRunner 将缓存未更改的上下文。我不知道具体是不是这种情况。

【讨论】:

  • 我试图删除 AnnotationConfigContextLoader,但没有删除表,全新安装会失败。所以创建前的drop是必要的。无论如何我都删除了 AnnotationConfigContextLoader,你可以说它是不必要的(我认为)。
  • 是的,在这种情况下,bean 被重新创建,这导致脚本被执行。数据库在同一运行中的跨测试内存中持久存在,这就是为什么需要 drop 语句的原因。
猜你喜欢
  • 2014-08-18
  • 2012-10-04
  • 2013-02-03
  • 2018-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 2011-05-12
相关资源
最近更新 更多