我有以下配置类:
@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数据库,因此仅一次应用程序上下文?
谢谢
答案 0 :(得分:3)
我认为您可以开始查看有关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并以编程方式创建嵌入式数据库。
我希望您会找到一些有用的参考。
答案 1 :(得分:2)
在单元测试中,您必须保证每个测试都独立于可重复的hance上下文。因此,只加载一次上下文不是一个好主意。最好在执行后重置。为此,您可以在测试类中使用 @DirtiesContext(classMode = ClassMode.AFTER_CLASS)
因此,当下一个junit类启动时,您将强制上下文重新启动
答案 2 :(得分:2)
我从Embedded Database Support的 Spring Boot 文档中找到了另一个好提示:
他们说:
如果您在测试中使用此功能,则可能会注意到 整个测试套件都会重复使用同一数据库,无论 您使用的应用程序上下文数。如果你想确定 每个上下文都有一个单独的嵌入式数据库,则应设置 将spring.datasource.generate-unique-name设置为true。
因此,要使每个EmbeddedDatabase
都是唯一的,您可以尝试使用:
EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
...
.build();
答案 3 :(得分:1)
因此失败的原因是,在作为清洁/安装的一部分运行测试时,数据库(H2)位于内存中。运行第一个测试后,创建/插入脚本已经执行。在此之后执行任何后续测试,将导致重新执行相同的脚本,并且会发生错误。
使用DROP TABLE IF EXISTS <table name>;
更新您的创建脚本。这样可以确保删除该表然后重新创建。
注意:我不确定为什么您明确指定了AnnotationConfigContextLoader
。我认为,如果没有这些内容,运行程序SpringJUnit4ClassRunner
将缓存未更改的上下文。我不知道是不是这种情况。