在不丢弃表的情况下擦除H2数据

时间:2016-02-03 16:34:52

标签: java spring junit h2

我正在为我的一个项目编写JUnit测试,测试都是用H2数据库完成的。

设置包括XML文件(包含spring bean和db setup),SQL文件(包含数据/模式)和java文件(只是测试)

每当运行JUnit测试套件时,由于重复数据(因为H2在内存中),一些测试会失败,我想知道是否有办法在某个类之前擦除H2数据?

@Stepwise

由于运行我们的一些测试所需的时间限制,我们已经尝试了它并不适用于我们的情况。

@DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_CLASS)

以上几乎是每个班级的设置或类似的构建。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("test.xml")
public class ABCTest {

    private static final Logger log = Logger.getLogger(ABC.class);

    @Autowired
    private ABCDao;

    ....

    @After
    public void tearDown(){
       ABCDao = null;
       ...
    }

    @Test
    public void test() {

    ...

    }

}

如果测试是单独运行的,那么套件因内存中的数据而失败就不会有问题。 我该如何解决这个问题?

3 个答案:

答案 0 :(得分:4)

此代码将有效擦除整个H2数据库(只需在使用@Before,JUnit规则等任何测试方法之前运行它:

public static void truncateAll(JdbcTemplate jdbcTemplate) throws SQLException {
    jdbcTemplate.execute("SET REFERENTIAL_INTEGRITY FALSE");

    try {
        Iterator var1 = getTableNames(jdbcTemplate).iterator();

        while(var1.hasNext()) {
            String tableName = (String)var1.next();
            jdbcTemplate.execute("TRUNCATE TABLE " + tableName);
        }
    } finally {
        jdbcTemplate.execute("SET REFERENTIAL_INTEGRITY TRUE");
    }

}

private static List<String> getTableNames(JdbcTemplate jdbcTemplate) throws SQLException {
    return (List)jdbcTemplate.execute(new ConnectionCallback() {
        public List<String> doInConnection(Connection conn) throws SQLException, DataAccessException {
            DatabaseMetaData metaData = conn.getMetaData();
            ResultSet tables = metaData.getTables((String)null, (String)null, "%", new String[]{"TABLE"});
            ArrayList tableNames = Lists.newArrayList();

            try {
                while(tables.next()) {
                    tableNames.add(tables.getString("TABLE_NAME"));
                }
            } finally {
                tables.close();
            }

            return tableNames;
        }
    });
}

答案 1 :(得分:1)

阅读本节:

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/integration-testing.html#testcontext-tx

基本上,每个测试都会回滚它所做的任何更改,因此每个测试都有一个新的数据库状态。

答案 2 :(得分:0)

使用该实用工具类在您的类中隔离tet:

TestIsolator.clearDatabase(jdbcTemplate);

实用程序类:

import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import lombok.experimental.UtilityClass;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;

/**
 * Вспомогательные методы для обеспечения изоляции тестов.
 */
@UtilityClass
public class TestIsolator {

    /**
     * Очистить базу от возможных рудиментов ранее выполненных тестов. Очищает все таблицы базы.
     */
    public void clearDatabase(JdbcTemplate jdbcTemplate) {
        clearDatabase(jdbcTemplate, getTableNames(jdbcTemplate));
    }

    /**
     * Очистить указанные таблицы от возможных рудиментов ранее выполненных тестов.
     */
    public void clearDatabase(JdbcTemplate jdbcTemplate, List<String> tableNames) {
        jdbcTemplate.execute("SET REFERENTIAL_INTEGRITY FALSE");
        tableNames.forEach(tableName -> {
            jdbcTemplate.execute("TRUNCATE TABLE " + tableName + " RESTART IDENTITY");
            jdbcTemplate.execute("ALTER SEQUENCE " + tableName + "_ID_SEQ" + " RESTART WITH 1");
        });
        jdbcTemplate.execute("SET REFERENTIAL_INTEGRITY TRUE");
    }

    /**
     * Получить список таблиц базы.
     */
    private List<String> getTableNames(JdbcTemplate jdbcTemplate) {

        Object tableNames = jdbcTemplate.execute((ConnectionCallback<Object>) callback -> {
            ArrayList<String> names = new ArrayList<>();

            try (ResultSet tables = callback.getMetaData().getTables(
                null, null, "%", new String[]{"TABLE"})) {
                while (tables.next()) {
                    names.add(tables.getString("TABLE_NAME"));
                }
            }

            return names;
        });

        return (List<String>) tableNames;
    }
}