在集成测试中,对于保存数据到数据库的方法,我们需要验证是否数据被正确地保存到数据库中。
对于使用 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 字段。
- 创建一个 final 类
DbTestUtil,然后通过一个私有构造器阻止实例化。 - 在
DbTestUtil中增加一个静态方法resetAutoIncrementColumns(),这个方法接受需要重置自增的表名,当前上下文,然后进行重置操作。
要实现这个类,我们需要
- 获得
DataSource的引用。 - 打开数据库连接。
- 执行重置语句。
下面是一个 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");
}
在Spring集成测试中,由于自增字段导致的数据验证难题可以通过多种方式解决。可以尝试忽略自增id,但在涉及关联数据时这种方法不可行。使用`@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)`虽然简单但会影响测试效率。另一种解决方案是创建一个帮助类,专门用于重置特定表的自增id,这将提高测试效率且不影响测试准确性。

1724

被折叠的 条评论
为什么被折叠?



