如何在spring test中的@Test方法之前只填充一次数据库?

Vol*_*kyi 21 java mysql spring spring-test

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

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

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

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

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

谢谢!

Mik*_*ler 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

请注意,这仍然是一个相当快速和肮脏的解决方案,处理数据库的合理方法符合Ralph的答案.

  • 使用最新版本的Spring不推荐使用`JdbcTestUtils.executeSqlScript(template,resource,true)`,你必须使用`org.springframework.jdbc.datasource.init.DatabasePopulator`(`ResourceDatabasePopulator`和`DatabasePopulatorUtils`) (4认同)

Ral*_*lph 11

使用Springs嵌入式数据库支持

<jdbc:embedded-database id="dataSource">
    <jdbc:script location="classpath:myScript.sql"/>
    <jdbc:script location="classpath:otherScript.sql"/>
</jdbc:embedded-database>
Run Code Online (Sandbox Code Playgroud)

或Springs初始化数据库支持

<jdbc:initialize-database data-source="dataSource">
    <jdbc:script location="classpath:myScript.sql"/>
    <jdbc:script location="classpath:otherScript.sql"/>
</jdbc:initialize-database>
Run Code Online (Sandbox Code Playgroud)

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


Ave*_*vec 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑:一个更好的解决方案。

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);
}
Run Code Online (Sandbox Code Playgroud)