22

我用junit4测试spring服务层的下一个问题是:如何在所有@Test方法之前调用只填充数据库一次的脚本:我想在所有@Tests之前执行一次:

JdbcTestUtils.executeSqlScript(jdbcTemplate(), new FileSystemResource(
"src/main/resources/sql/mysql/javahelp-insert.sql"), false);

我尝试在我的 GenericServiceTest 类(由测试类扩展)上使用 @PostConstruct。事实证明,@PostConstruct 每次在每个 @Test 方法之前都会被调用。有趣的是,甚至在每个 @Test 方法之前都会调用 GenericServiceTest 的 @Autowired 注释方法。

我不想在每个测试类之前填充数据库,但只在 spring-test 启动时填充一次。

如何在所有带有spring测试框架和junit4的@Test方法之前只执行一次上述方法?

谢谢!

4

5 回答 5

13

基于 Alfredos 的回答,这是一种无需调用嵌入式数据库的默认脚本即可注入数据库信息的方法。例如,当您想为您自动构建 DDL 时,这可能很有用 - 至少在测试中是这样。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/applicationContext.xml"})
public class TestClass {

    @Autowired
    private ApplicationContext ctx;

    private JdbcTemplate template;

    @Autowired
    public void setDataSource(DataSource dataSource) {
       template = new JdbcTemplate(dataSource);
    }

    private static boolean isInitialized = false;

    @Before
    public void runOnce() {
        if (isInitialized) return;
        System.out.println("Initializing database");

        String script = "classpath:script.sql"; 
        Resource resource = ctx.getResource(script);
        JdbcTestUtils.executeSqlScript(template, resource, true);            
        isInitialized = true;
    }
}

这样,该runOnce()方法被调用一次,并且仅一次用于测试运行。如果您创建isInitialized一个实例字段(非静态),则该方法将在每次测试之前调用。这样,如果需要,您可以在每次测试运行之前删除/重新填充表。

请注意,这仍然是一个相当快速和肮脏的解决方案,并且处理数据库的明智方法是根据 Ralph 的回答。

于 2013-11-12T11:23:21.050 回答
11

使用 Springs 嵌入式数据库支持

<jdbc:embedded-database id="dataSource">
    <jdbc:script location="classpath:myScript.sql"/>
    <jdbc:script location="classpath:otherScript.sql"/>
</jdbc:embedded-database>

或 Springs 初始化数据库支持

<jdbc:initialize-database data-source="dataSource">
    <jdbc:script location="classpath:myScript.sql"/>
    <jdbc:script location="classpath:otherScript.sql"/>
</jdbc:initialize-database>

@参见http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/jdbc.html#jdbc-embedded-database-support

于 2013-07-07T09:29:19.647 回答
5

示例基于 Mike Adlers 示例,但适用于 JUnit 5,并使用了 Tugdual 提到的 ResourceDatabasePopulator。

为每个测试方法创建一次测试类。因此,如果您只想填充一次,您需要以某种方式处理它。这里是用一个静态变量完成的。

@Autowired
private DataSource dataSource;

private static boolean isInitialized;

@BeforeEach // JUnit 5
void initDatabase() {
  if(!isInitialized) { // init only once
    ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
    populator.addScript(new ClassPathResource("/sql/myscript.sql")));
    populator.execute(dataSource);
    isInitialized = true;
  }
}

编辑:更好的解决方案。

Junit 5提供了其他人提到的@BeforeAll,应该是正确的答案

@Autowired
private DataSource dataSource;

@BeforeAll // JUnit 5
void initDatabase() {
  ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
  populator.addScript(new ClassPathResource("/sql/myscript.sql")));
  populator.execute(dataSource);
}
于 2019-09-30T11:25:14.203 回答
3

如果您是 Spring Boot,您可以通过以下方式在测试之前提及要启动的多个脚本

spring.datasource.data=classpath:accounts.sql, classpath:books.sql, classpath:reviews.sql
于 2018-05-23T12:21:22.660 回答
0

您可以使用 JUnit 5 的 @BeforeAll 注释

于 2020-05-24T19:08:05.380 回答