【问题标题】:DbUnit check autogenerating idDbUnit 检查自动生成的 id
【发布时间】:2025-12-03 22:50:01
【问题描述】:

我需要使用 DbUnit 执行集成测试。我已经创建了数据集(测试前后)并使用@DatabaseSetup@ExpectedDatabase 注释进行比较。在测试期间,创建了一个新的数据库行(它出现在测试数据集中,我使用@ExpectedDatabase 注释指定)。问题是行 ID 是自动生成的(我使用的是 Hibernate),所以行 ID 正在永久更改。因此我的测试只通过了一次,之后我需要在测试数据集中更改 id,但这不是我需要的。如果这个问题可以用 DbUnit 解决,你能建议我解决这个问题吗?

【问题讨论】:

  • 我也遇到过类似的问题,你有没有想出解决办法?
  • 我忽略了 id 断言。请参阅解决方案 B(下面的答案)。对于我的测试用例,这样的断言不是必需的。
  • 如何在注解中集成assertEqualsIngoreColumns()?顺便说一句,我还发现在数据源连接的数据库中使用内存数据库也是一种替代选择,因为内存数据库将在每次运行测试时进行初始化。

标签: spring hibernate dbunit


【解决方案1】:

解决方案 A:

使用分配的 id 策略并使用单独的查询来检索业务逻辑中的下一个值。因此,您始终可以通过一些适当的数据库清理在持久性测试中分配一个已知的 id。请注意,这仅在您使用 Oracle 序列时才有效。

解决方案 B:

如果我没记错的话,org.dbunit.Assertion 中有一些类似于assertEqualsIngoreColumns() 的方法。因此,如果您不介意,可以忽略 id 断言。通常我会通过对 id 进行非空检查来弥补这一点。 @ExpectedDatabase 中可能有一些选项,但我不确定。

解决方案 C:

我想知道是否有更好的解决方案,因为解决方案 A 会带来一些性能开销,而解决方案 B 会牺牲一点测试覆盖率。

顺便说一下,您使用的是什么版本的 dbunit。我在 2.4.9 及以下版本中从未见过这些注解,它们看起来更易于使用。

【讨论】:

    【解决方案2】:

    这个解决方法一直在拯救我的皮肤:

    我实现了一个带有替换功能的 AbstractDataSetLoader:

    public class ReplacerDataSetLoader extends AbstractDataSetLoader {
        private Map<String, Object> replacements = new ConcurrentHashMap<>();
    
        @Override
        protected IDataSet createDataSet(Resource resource) throws Exception {
            FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
            builder.setColumnSensing(true);
            try (InputStream inputStream = resource.getInputStream()) {
                return createReplacementDataSet(builder.build(inputStream));
            }
        }
    
        /**
         * prepare some replacements
         * @param dataSet
         * @return
         */
        private ReplacementDataSet createReplacementDataSet(FlatXmlDataSet dataSet) {
            ReplacementDataSet replacementDataSet = new ReplacementDataSet(dataSet);
    
            //Configure the replacement dataset to replace '[null]' strings with null.
            replacementDataSet.addReplacementObject("[null]", null);
            replacementDataSet.addReplacementObject("[NULL]", null);
            replacementDataSet.addReplacementObject("[TODAY]", new Date());
            replacementDataSet.addReplacementObject("[NOW]", new Timestamp(System.currentTimeMillis()));
    
            for (java.util.Map.Entry<String, Object> entry : replacements.entrySet()) {
                replacementDataSet.addReplacementObject("["+entry.getKey()+"]", entry.getValue());
            }
            replacements.clear();
    
            return replacementDataSet;
        }
    
        public void replace(String replacement, Object value){
            replacements.put(replacement, value);
        }
    }
    

    有了这个,你可以以某种方式跟踪你需要的 id 并在你的睾丸中替换

    @DatabaseSetup(value="/test_data_user.xml")
    @DbUnitConfiguration(dataSetLoaderBean = "replacerDataSetLoader")
    public class ControllerITest extends WebAppConfigurationAware {
    
        //reference my test dbconnection so I can get last Id using regular query
        @Autowired
        DatabaseDataSourceConnection dbUnitDatabaseConnection;
        //reference my datasetloader so i can iteract with it
        @Autowired
        ColumnSensingFlatXMLDataSetLoader datasetLoader;
    
    
        private static Number lastid = Integer.valueOf(15156);
        @Before
        public void setup(){
            System.out.println("setting "+lastid);
            datasetLoader.replace("emp1", lastid.intValue()+1);
            datasetLoader.replace("emp2", lastid.intValue()+2);
        }
    
        @After
        public void tearDown() throws SQLException, DataSetException{
            ITable table = dbUnitDatabaseConnection.createQueryTable("ids", "select max(id) as id from company.entity_group");
            lastid = (Number)table.getValue(0, "id");
        }
    
        @Test
        @ExpectedDatabase(value="/expected_data.xml", assertionMode=DatabaseAssertionMode.NON_STRICT)
        public void test1() throws Exception{
            //run your  test logic
        }
    
        @Test
        @ExpectedDatabase(value="/expected_data.xml", assertionMode=DatabaseAssertionMode.NON_STRICT)
        public void test2() throws Exception{
            //run your  test logic
        }
    }
    

    我预期的数据集需要一些替换 emp1 和 emp2

    <?xml version='1.0' encoding='UTF-8'?>
    <dataset>
    
        <company.entity_group ID="15155" corporate_name="comp1"/>
        <company.entity_group ID="15156" corporate_name="comp2"/>
        <company.entity_group ID="[emp1]" corporate_name="comp3"/>
        <company.entity_group ID="[emp2]" corporate_name="comp3"/>
        <company.ref_entity ID="1" entity_group_id="[emp1]"/>
        <company.ref_entity ID="2" entity_group_id="[emp2]"/>
    
    </dataset>
    

    【讨论】:

      【解决方案3】:

      使用 DatabaseAssertionMode.NO_STRICT,并从“expect.xml”中删除“id”列。 DBUnit 将忽略此列。

      【讨论】: