Terminating a fluent interface

I  usually use a fluent interface to make assertion on data on database, a typical assertion looks like

1
2
3
4
5
DbAssert.OnQuery("select *  from tablename")
   .That("column1", Is.EqualTo(15))
   .That("column2", Is.EqualTo(90))
   .That("column2", Is.EqualTo(99))
   .ExecuteAssert();

This makes me possible to express simple database assertion to verify database conditions expressed by a series of Nunit.Constraints on field of a query, it is very useful when I have to test stored procedures or verify that NHibernate mappings works as expected. If you look closely to the syntax it terminate with a ExecuteAssert call that actually does the assertion. This kind of syntax makes me a little worried, because you can write an assertion like this

1
2
3
4
DbAssert.OnQuery("select *  from tablename")
   .That("column1", Is.EqualTo(15))
   .That("column2", Is.EqualTo(90))
   .That("column2", Is.EqualTo(99));

This is a perfectly valid code, it created a DbAssert object but never execute it, thus the assertion always succeed and never fail because it gets never executed. A possibility is to make the object DbAssert****disposable, so you can use inside a using, but the syntax will get worse. A viable solution is a little modification

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
private static DbAssert theQuery;

public static DbAssert OnQuery(String query)
{
    if (theQuery != null) Assert.Fail("");
    return theQuery = new DbAssert(query);
}
...
public void ExecuteAssert()
  {
     theQuery = null;

This code checks if it is a previous query created and if one query is still there, you are in situation where the previous database assertion was not executed, so you can make the test fail. This solution is still not so good because it fails the test immediatly following the one that forget to execute the assertion, but at least you know that something is wrong.

The final solution is to create a real Nunit constraint to have this syntax

1
2
3
4
5
Assert.That("select *  from tablename",
  DbAssert.CreateConstraint()
   .That("column1", Is.EqualTo(15))
   .That("column2", Is.EqualTo(90))
   .That("column2", Is.EqualTo(99)));

I still have a fluent interface to specify the assertion, but now everything is included into an Assert.That, it makes not possible to forget the call to ExecuteAssert, the error contains all fields that have not expected result. Then you can do some simple hack to intercept the original message of the original criterion to have a failing output like this

1
2
3
4
  Expected:   Expected: "column1 = 15"
  But was:  150
  Expected: "column2 = 90"
  But was:  98

But if you use a Greater Than or some other constraint the result is

1
2
3
4
  Expected:   Expected: "column1 greater than 150"
  But was:  15
  Expected: "column2  =  980"
  But was:  98

As you can see the error detail contains all the field that does not match as well as detailed information. With this little helper I can write concise assertion on database data.

Alk.

Tags: NUnit Testing Fluent Interface

DotNetKicks Image