[英]How to load application context for testing Spring application with JUnit 4?
[英]Junit Spring avoid to load twice application context datasource
我有这个配置类:
@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 数据库和应用程序上下文一次?
谢谢
我认为您可以开始查看有关集成测试的 Spring 文档。
将事务测试用于集成测试 ( @Transactional
) 也是一个很好的做法,它在每个测试结束时回滚:请参阅事务管理。
为了避免为每个测试类重新创建ApplicationContext
的成本,可以按照此处的说明使用缓存: 上下文缓存。
对于嵌入式数据库的集成测试,您还可以找到文档: 使用嵌入式数据库测试数据访问逻辑。 来自上一个链接的注释,与您的用例相匹配:
但是,如果您希望创建在测试套件内共享的嵌入式数据库,请考虑使用 Spring TestContext Framework 并将嵌入式数据库配置为 Spring ApplicationContext 中的 bean,如使用 Spring XML 创建嵌入式数据库和创建嵌入式数据库中所述以编程方式嵌入数据库。
我希望你能找到一些有用的参考。
我从嵌入式数据库支持的Spring Boot文档中发现的另一个好技巧:
他们说 :
如果您在测试中使用此功能,您可能会注意到,无论您使用多少应用程序上下文,整个测试套件都会重用同一个数据库。 如果要确保每个上下文都有单独的嵌入式数据库,则应将 spring.datasource.generate-unique-name 设置为 true。
因此,为了使每个EmbeddedDatabase
独一无二,您可以尝试使用以下命令创建它们:
EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
...
.build();
在单元测试中,您必须保证每个测试都是可重复的,并且与上下文无关。 因此,仅加载一次上下文并不是一个好主意。 执行后最好复位。 为此,您可以在测试类中使用@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
因此,当启动下一个 junit 类时,您将强制您的上下文重新启动
因此,失败的原因是当您将测试作为清理/安装的一部分运行时,数据库 (H2) 驻留在内存中。 创建/插入脚本在第一个测试运行后已经执行。 在此之后的任何后续测试执行都将导致重新执行相同的脚本并且会发生错误。
使用DROP TABLE IF EXISTS <table name>;
更新您的创建脚本DROP TABLE IF EXISTS <table name>;
. 这将确保该表被删除然后重新创建。
注意:我不确定您为什么明确指定AnnotationConfigContextLoader
。 我认为,没有它,运行程序SpringJUnit4ClassRunner
将缓存尚未更改的上下文。 我不知道具体是否是这种情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.