The following is a constraint that checks for nulls in a
DataTable, whether a column is not null or must only be null. The constraint has
two constructors, one for the column name or index, and one for whether to
check for nulls or not nulls, as shown below.
Listing 4
public class DataTableNullConstraint: NUnit.Framework.Constraints.Constraint
{
private int _columnIndex = - 1;
private string _columnName = null;
private bool _notNull = true;
public DataTableNullConstraint(string columnName, bool notNull)
{
_columnName = columnName;
_notNull = notNull;
}
public DataTableNullConstraint(int columnIndex, bool notNull)
{
_columnIndex = columnIndex;
_notNull = notNull;
}
}
The constraint uses the WriteDescriptionTo method to write a
message line about the actual problem (whether the table has a null or not null
value), using the MessageWriter object to write the message.
Listing 5
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.WriteMessageLine("The data table contains a {0} value",
_notNull ? "null" : "not null");
}
The matching of the object, in the Matches method, parses
the table (passed in through the parameter) and determines whether fields have
or do not have null values for a column.
Listing 6
public override bool Matches(object actual)
{
base.actual = actual;
if (actual == null || !(actual is DataTable))
throw new ArgumentException("Actual value is not a DataTable", "actual");
DataTable table = actual as DataTable;
foreach (DataRow row in table.Rows)
{
bool isNull = !string.IsNullOrEmpty(_columnName) ? row.IsNull(_columnName):
row.IsNull(_columnIndex);
if ((_notNull && isNull) || (!_notNull && !isNull))
return false;
}
return true;
}
The first statement of this method is recommended by the
NUnit documentation, assigning the actual value to the base method. It also
validates the actual value, and if not a data table, an exception is thrown.
For each row in the table, if the column or index value is null
or not null (depending on what is being searched for), a false is returned
indicating a problem. When a false is returned to the caller, through Assert.That(),
a false value means that an AssertionException exception is raised. How this
constructor is exposed is through a static assert class. Below is the method
that looks for nulls:
Listing 7
public static void ColumnIsNotNull(DataTable table, string columnName,
string message, params object[] parameters)
{
ColumnIs(table, columnName, true, message, parameters);
}
public static void ColumnIsNotNull(DataTable table, int columnIndex,
string message, params object[] parameters)
{
ColumnIs(table, columnIndex, true, message, parameters);
}
I left out the other four overloads for brevity, as they
pass the information directly along. The private ColumnIs global methods use
the Assert.That method, creating a constraint and passing along the message parameters.
Listing 8
private static void ColumnIs(DataTable table, string columnName, bool notNull,
string message, params object[] parameters)
{
Assert.That(table, new DataTableNullConstraint(columnName, notNull),
message, parameters);
}
private static void ColumnIs(DataTable table, int columnIndex, bool notNull,
string message, params object[] parameters)
{
Assert.That(table, new DataTableNullConstraint(columnIndex, notNull),
message, parameters);
}
If Matches returns false, an AssertionException is thrown
and a call to the WriteDescriptionTo method renders any error details. That was
a simplistic illustration. Let us now take a look at one that uses reflection.
I also built a ReflectionAssert which has the ability to compare two object's
properties to ensure they are the same.
Listing 9
public override bool Matches(object actual)
{
base.actual = actual;
if (actual == null)
throw new ArgumentNullException("actual");
if (!string.IsNullOrEmpty(_propertyName))
{
PropertyInfo prop = _expectedObject.GetType().GetProperty(_propertyName);
if (prop == null)
throw new ArgumentNullException("prop");
return prop.GetValue(_expectedObject, null).Equals(prop.GetValue(actual,
null));
}
else
{
PropertyInfo[]props = _expectedObject.GetType().GetProperties();
if (props == null || props.Length == 0)
throw new ArgumentNullException("props");
foreach (PropertyInfo prop in props)
{
if (!prop.GetValue(_expectedObject, null).Equals(prop.GetValue(actual,
null)))
return false;
}
return true;
}
}
This example can be used to parse a single property, or
parse multiple property values, depending on what expected criteria is
provided. If parsing all properties and only one of the values does not match,
then a false value is returned; otherwise, true is returned.