Spring Test 中重置自增字段

来源:互联网 发布:西安广电网络营业厅 编辑:程序博客网 时间:2024/05/17 21:43

在集成测试中,对于保存数据到数据库的方法,我们需要验证是否数据被正确地保存到数据库中。

对于使用 Spring 的项目,可以使用 Spring Test DbUnit 和 DbUnit 进行测试。

然而,在数据对比的时候,自增的字段就成了一个障碍,因为自增字段是自动生成的,在测试的时候,我们无法确定下一个插入数据的自增字段的值。

尝试忽略自增 id

首先,我们考虑忽略自增 id,在 @ExpectedDatabase 注解中设置 assertionMode = DatabaseAssertionMode.NON_STRICT ,就会忽略数据集中没有显示声明的字段。但是每一行数据都必须拥有一致的字段。比如

<dataset>    <clazz name="clazz1"/>    <clazz name="clazz2"/></dataset>

这看起来没有什么大问题,id 会在插入数据的时候自动生成。但是,假设我们有一个学生表,每个学生对应一个班级,问题就来了。比如我们有如下数据集:

<dataset>    <clazz name="clazz1"/>    <clazz name="clazz2"/>    <student name="student1"/>    <student name="student2"/></dataset>

这个数据集无法完成初始化,因为我们不知道班级的 id,学生数据就无法插入数据库。所以,我们无法在测试中忽略自增 id。

使用 @DirtiesContext

一个很容易的方法就是使用 Spring 的 @DirtiesContext 注解,然后设置 classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD ,这样会在每个测试方法开始前重新载入新的上下文,包括我们的数据库。这种配置看起来如下

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = {PersistenceContext.class})@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,        DirtiesContextTestExecutionListener.class,        TransactionalTestExecutionListener.class,        DbUnitTestExecutionListener.class })@DbUnitConfiguration(dataSetLoader = ColumnSensingReplacementDataSetLoader.class)@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)public class ITTodoRepositoryTest {}

即使这种方法很简单,也解决了我们的问题,但显而易见的是这会降低我们测试的效率,因为每一个测试方法都重新载入一个新的上下文,如果对测试效率有要求,这种方法就不是太适用了。

创建一个能重置自增的帮助类

我们可以创建一个帮助类,来重置指定表的自增 id 字段。

  1. 创建一个 final 类 DbTestUtil ,然后通过一个私有构造器阻止实例化。
  2. DbTestUtil 中增加一个静态方法 resetAutoIncrementColumns() ,这个方法接受需要重置自增的表名,当前上下文,然后进行重置操作。

要实现这个类,我们需要

  1. 获得 DataSource 的引用。
  2. 打开数据库连接。
  3. 执行重置语句。

下面是一个 DbTestUtil 示例

public final class DbTestUtil {    private static final String resetSqlTemplate = "ALTER TABLE %s ALTER COLUMN id RESTART WITH 1";    private DbTestUtil() { }    public static void resetAutoIncrementColumns(ApplicationContext applicationContext,                                                 String... tableNames) throws SQLException {        DataSource dataSource = applicationContext.getBean(DataSource.class);        try (Connection dbConnection = dataSource.getConnection()) {            for (String resetSqlArgument : tableNames) {                try (Statement statement = dbConnection.createStatement()) {                    String resetSql = String.format(resetSqlTemplate, resetSqlArgument);                    statement.execute(resetSql);                }            }        }    }}

这里的重置语句是 H2 数据库的语法。有了这个方法后,我们在测试前就可以进行调用。

@Beforepublic void setUp() throws SQLException {    DbTestUtil.resetAutoIncrementColumns(applicationContext, "student", "clazz");}
原创粉丝点击