Question

I need to execute integration tests using DbUnit. I have created to datasets (before and after test) and compare them using @DatabaseSetup and @ExpectedDatabase annotations. During test one new database row was created (it presents in after test dataset, which I specify using @ExpectedDatabase annotation). The problem is that row id is generating automatically (I am using Hibernate), so row id is changing permanently. Therefore my test pass only once and after that I need to change id in after test dataset, but this is not that I need. Can you suggest me please any solutions for this issue, if this issue can be resolved with DbUnit.

Was it helpful?

Solution

Solution A:

Use assigned id strategy and use a seperate query to retrieve next value in business logic. So you can always assign a known id in your persistence tests with some appropriate database cleanup. Note that this only works if you're using Oracle Sequence.

Solution B:

If I'm not mistaken, there are some methods similar to assertEqualsIngoreColumns() in org.dbunit.Assertion. So you can ignore the id assertion if you don't mind. Usually I'll compensate that with a not null check on id. Maybe there some options in @ExpectedDatabase but I'm not sure.

Solution C:

I'd like to know if there is a better solution because that solution A introduces some performance overhead while solution B sacrifices a little test coverage.

What version of dbunit you're using by the way. I have never seen these annotations in 2.4.9 and below, they looks easier to use.

OTHER TIPS

This workaround is saving my skin till now:

I implemented a AbstractDataSetLoader with replacement feature:

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);
    }
}

With this you could somehow track the ids you need and replace in your testes

@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
    }
}

And my expected dataset need some replacement emp1 and 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>

Use DatabaseAssertionMode.NO_STRICT, and delete the 'id' column from your 'expect.xml'. DBUnit will ignore this column.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top