When you’re developing code that accesses a database (and in an enterprise world: who isn’t?), it is often difficult to write good unit-tests, as these tests depend on the data that is currently present in the database. A test that runs just fine now, might fail as soon as someone changes the data.

Therefore, a framework like DbUnit was developed: it allows you to define which data should be present when your tests are run. In fact, a typical usage is to reset the database (data-wise, that is), before every test. By ‘reset’, I actually mean: clear all data and reread a predefined set from file (typically xml). As I have had some good results with DbUnit, I was happy to find out that a port to .NET was underway: NDbUnit. However, when I tried to use it, I found (and fixed) some bugs in the code.

I’ll list them here for future reference and in the hope these fixes make it to the next release.

DbOperation.cs

The code in insertRecursive/deleteRecursive that adds the name of the current table to the hashtable (in order to prevent a table from being processed twice), should be immediately after the test instead of at the end of the method:


if (deletedTableColl.ContainsKey(dataTableSchema.TableName))
return;
}
insertedTableColl[dataTableSchema.TableName] = null;

As both methods will try to process related tables first (to enforce constraints), an infinite loop occurs when a table has a hierarchical relation with itself.

DbOperation.cs

insertRecurcive should also try to add the parent relations first:


DataRelationCollection parentRelations = dataTableSchema.ParentRelations;
if (null != parentRelations)
{
foreach (DataRelation parentRelation in parentRelations)
{
// Must insert parent table first.
insertRecursive(ds, parentRelation.ParentTable, dbCommandBuilder,
dbTransaction, insertedTableColl,
insertIdentity);
}
}

SqlDbCommandBuilder
The System.Console.Writeln should be removed from getSchemaTable as it hides the exact information of what went wrong. Just let the exception bubble-up to the caller (CreateSelectCommand in this case) and catch it there. So, instead of checking the return value as in:


_dataTableSchema = getSchemaTable(sqlSelectCommand);
if (_dataTableSchema == null)
{
string message = String.Format(@"SqlDbCommandBuilder.CreateSelectCommand(DataSet, string)
failed for tableName = '{0}'", tableName);
...
}

a try/catch block should be used to wrap the exception and add some extra information:


try
{
_dataTableSchema = getSchemaTable(sqlSelectCommand);
}
catch (Exception e)
{
string message = String.Format("SqlDbCommandBuilder.CreateSelectCommand(DataSet, string) failed for tableName = '{0}'", tableName);
throw new NDbUnitException(message, e);
}

Advertisements