Constraint-Based Asserts and NUnit


In this post I will concentrate on NUnit and it’s “new” feature. Well not exactly new,  but a feature that are around since version 2.4 (current version is 2.5.2). This feature, that I would like to present here, is the constraints based assertion.

Before we start with the new and shiny let’s look at the old and proven.

[Test]
public void FooTest()
{
  var result = DoSomething();

  Assert.AreEqual("something", result.Text);
}

This is what we know and this is what we work with. The problem is that people manage to confuse the expected and actual parameters of the assert statement. Which then results in funny little mishaps. But this is not the theme of this post.

What I would like to show here is the constraint based assertion. To get us into the subject here is a little example.

[Test]
public void FooTest()
{
  var result = DoSomething();

  Assert.That(result, Is.EqualTo("something"));
}

Looks nice and it is. What I find good is that it gets harder to confuse the expected and actual values.

The best thing is that you can chain the constraints. This would then look like the following.

[Test]
public void FooTest()
{
  var result = DoSomething();

  Assert.That(result, Is.Not.EqualTo("gnihtemos"));
}

The next thing is not really in context with the posts title but I think that it is such a nice feature that it is worth mentioning. The “thing” in question is the exception assertion. To get the record straight I find nothing wrong with the ExpectedExceptoin attribute but this new version is just cleaner.

So as before lets look at the old and proven before we take a look at the new and shiny. The old and proven would look like this.

[Test]
[ExpectedException(typeOf(SomeException))]
public void ExceptionTest()
{
  ThrowsSomething();
}

This is nice and nicely extendable. What they came up with is a non attribute version that works really well.

[Test]
public void ExceptionTest()
{
  Assert.Throws<SomeException>(() => ThrowsSomething());
}

This is nice and becomes quite readable without being to invasive. And I personally quickly fell in love with this way of testing for exceptions.

With this much goodness there has to be something bad. And there is. What you will find hard to do is to integrate your custom constraints into NUnit. You actually have two variants how to use your custom constraints without poking into the framework itself.

Option one is to use a build in construct and get code that would look something like this.

[Test]
public void MyCustomConstraintTest()
{
  MyObject result = DoCustomStuff();

  MyConstraint constraint = new MyConstraint();
  Assert.That(result, Has.Some.Matches(constraint));
}

And option two which requires less code but does not look that good.

[Test]
public void MyCustomConstraintTest()
{
  MyObject result = DoCustomStuff();

  Assert.That(result, new MyConstraint(););
}

There is always the option to hack at the framework and integrate your custom constraint. But I would not recommend it.

As a last thing lets take a look at how you can write your own constraint. It is actually quite simple. All you have to do is to derive from the Constraint class. The base class itself is abstract and features many methods that you can override. But in most cases you will just need the two abstract ones.

Your custom constraint could look something like this:

public class MyConstraint : Constraint
{
  public bool Matches(object actual)
  {
    if(actual is MyObject)
      return ((MyObject)actual).Quantity > 0 ? true : false;
    return false;
  }

  public void WriteDescriptionTo(MessageWriter writer)
  {
    writer.write("MyConstraint failed");
  }
]

So this is the gist of it. I hope that you got a little insight into the new features of NUnit.

All that is now left to do is to use it 🙂

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s