Spring Test 中重置自增字段

在Spring集成测试中,由于自增字段导致的数据验证难题可以通过多种方式解决。可以尝试忽略自增id,但在涉及关联数据时这种方法不可行。使用`@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)`虽然简单但会影响测试效率。另一种解决方案是创建一个帮助类,专门用于重置特定表的自增id,这将提高测试效率且不影响测试准确性。

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

对于使用 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 数据库的语法。有了这个方法后,我们在测试前就可以进行调用。

@Before
public void setUp() throws SQLException {
    DbTestUtil.resetAutoIncrementColumns(applicationContext, "student", "clazz");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值