Background
Back in September 2009, I had written a blog post about comparison of unit testing frameworks. In that post I had compared NUnit and MS Testing unit testing frameworks for Dot Net. For the purpose of demonstration I had taken a sample BankAccount class with very basic methods like Deposit and Withdraw. I had used the assertions from both these unit testing frameworks. There were minor differences in syntax between the two. In this post I am going to use a library named Should.
Should is a unit testing framework agnostic assertion library. This means that the asserts used to verify the behavior of system under test can remain the same even if the testing framework changes. To take an example let me take a code snippet from the test project using MS Test framework.
Assert.AreEqual<int>(accountID, bankAccount.AccountID);
Assert.AreEqual<string>(accountHolder, bankAccount.AccountHolder);
The same test written in test project using NUnit is
Assert.AreEqual(accountID, bankAccount.AccountID);
Assert.AreEqual(accountHolder, bankAccount.AccountHolder);
Recent versions of NUnit also supports fluent asserts and the above lines of code can be re written as
Assert.That(bankAccount.AccountID, Is.EqualTo(accountID));
Assert.That(bankAccount.AccountHolder, Is.EqualTo(accountHolder));
This syntax reads far better than the earlier one. But still it is not very good. It looks as if we are still talking in terms of compiler language and not in terms of domain or business terms. Should helps us overcome this limitations by providing a very simple assertions.
How to use Should library
First of all we need to get the Should.dll and Should.Fluent.dll if we wish to use the fluent syntax. Both these dlls are freely available at the codeplex project site http://should.codeplex.com. Without wasting too much time lets see how can make use of this library in our tests.
Here is how I would refactor the MS Test project code to accommodate assertions using Should
[TestMethod]
public void AccountConstructorTest()
{
// Arrange - NA
const int expectedBalance = 1000;
// Act
Account bankAccount = new Account();
//// Assert
// Assert.IsNotNull(bankAccount, "Account was null.");
// Assert.AreEqual<int>(expectedBalance, bankAccount.AccountBalance, "Account balance not mathcing");
bankAccount.ShouldNotBeNull("Account was null");
bankAccount.AccountBalance.ShouldEqual(expectedBalance, "Account balance not matching");
}
As we can see I have commented the old code which was using MS Test style asserts. Lets check the refactored code which was developed using NUnit unit testing framework
[Test]
public void AccountConstructorTest()
{
// Arrange - NA
const int expectedBalance = 1000;
// Act
Account bankAccount = new Account();
// Assert
// Assert.IsNotNull(bankAccount, "Account was null.");
// Assert.AreEqual(expectedBalance, bankAccount.AccountBalance, "Account balance not mathcing");
bankAccount.ShouldNotBeNull("Account was null");
bankAccount.AccountBalance.ShouldEqual(expectedBalance, "Account balance not matching");
}
If you compare the two code snippets you can see that the test code looks exactly the same.
I have refactored the code in both the MS Test as well as the NUnit projects and uploaded them for the reference.
Conclusion
I am obsessed with clean code and unit testing. In general I like to follow Agile practices as much as possible and believe that unit testing is at the heart of Agile development. These small little things go a long way in making developers life easier. With libraries like Should it becomes very easy to switch unit testing framework from NUnit to others like MS Test or XUnit.
People who are familiar with Behavior Driven Development (BDD) will be able to relate better to this style of asserts.
If I were to port all the tests written using MS Test and Should assertion library over to NUnit framework probably the only change I would need to make is to change the attributes used to decorate the test classes and methods. This relieves us from making use of framework specific stuff like Collection Asserts which are available in NUnit. We are no more bound to a specific testing framework.
Should also supports a very fluent assertion syntax. I’ll leave it probably for a future post. If you can’t wait till then I would suggest have a look at the Should documentation and it should be fairly easy to use it if you have any other libraries which supports Fluent interface like Automapper or Rhino Mocks.
As always I have uploaded the complete source code to dropbox as BankAccountWithShouldLibrary.zip.
Until next time Happy Programming :)
"This syntax reads far better than the earlier one. But still it is not very good. It looks as if we are still talking in terms of compiler language and not in terms of domain or business terms. Should helps us overcome this limitations by providing a very simple assertions."
ReplyDeleteI Would dispute this, you are merely turning the "sentence around"...
"Confirm that bank account is not null"
"Confirm that bank account account balance is equal to expected balance"
Notice that I replaced "Assert" with a Synonym, since I fear that is where your mind might think in terms of "Assert" being something with code and compilers, when it is merely a word we could replace with "Confirm", "Guarantee" "Insist" depending on what you best like, they are somewhat all synonyms.
Now how is that "compiler language"?...
The later has some bad English in it it seems, but that is more due to your model than NUnit (a bank account should properly have a Balance rather than an Account Balance), this is the same for your "should" case however. Where I believe that it "Should be equal" rather than "Should equal".
Should is actually a poor choice, must would be a better word then as should is more a polite request that it is and in terms of testing i am fairly sure we really want it to be...