Wednesday, May 28, 2014

[C# - Unit Tests] NFluent : A tool to write much clearer Unit Tests !

NFluent is an Assertion library (http://www.n-fluent.net), which can be used in conjunction with all the common Unit Test Frameworks on the market (NUnit, MSTest, xUnit, …). It greatly simplifies the writing of good Unit Tests, which are clear and easy to understand, meaning also that they can be debugged more easily and efficiently.

image

It is common knowledge that writing good unit tests with good granularity and good coverage is a pre-requisite for high quality code – and in the end high quality applications. But even though most of the developers know that they should write them, there are barriers and developers do not like at all to do this task. Let us understand why that is the case and how NFluent can help us to overcome this problem !

Here is an example of a very simple Unit Test using the MSTest Framework :

image

The writing of Unit Tests is not very intuitive and natural. If you have applied naming conventions to your classes and methods (which you should always do !!) this might help you a little bit. But in general Unit Tests by themselves are not really self-explaining. In more complex contexts, developers have to understand in detail how the underlying classes and methods work to understand what has been tested and why it has been tested like this.

What if there were a way of writing your Unit Tests so that you can easily understand them in one line, without the need to check back in your class and method definition ? It would be great ? Well that is where NFluent comes into play !

NFluent is using a natural syntax to ease Unit Test development

Let us rewrite the last example using the NFluent syntax :

image

The most important line here is : Check.That<int>(result).IsEqualTo(4);

To understand what has been tested you just have to read the line, as you would do when reading a book ! The test is going to “Check that result (of type int) is equal to 4”. No ambiguity is possible, the test is directly human readable.

Let us see how easy it can get to understand when applying the NFluent syntax, so do you understand what the following tests are doing ?

  • Check.That<Calculator>(calculator).IsInstanceOf<Calculator>();
  • Check.That(value).IsPositive().And.Not.IsGreaterThan(80);
  • Check.That(numbers).IsOnlyMadeOf(1, 2, 3).And.HasSize(10);
  • Check.That(() => { throw new Exception("message"); }).Throws<Exception>().WithMessage("message");

That was easy right ? Try to identify the difference between these two tests :

  • Check.That<User>(user1).IsEqualTo<User>(user2); 
  • Check.That<User>(user1).HasFieldsWithSameValues(user2);

This is also very easy to do : the first test is comparing objects references while the second is comparing all the properties of the two user instances.

Clear error messages if checks fail

So what happens if checks fail when using NFluent? You get very meaningful and clear error messages, which help you understand why a test has failed. You may then modify your code very quickly to assure that it provides the expected behavior.

Here are some examples of failed unit test, see for yourself if you understand why they have failed :

  • The checked enumerable has 9 elements instead of 10.
  • The checked enumerable: [1, 2, 3]
  • The checked value is greater than the threshold.
  • The checked value: [100]
  • The expected value: less than [10]
  • The checked enumerable does not contain exactly the expected value(s).
  • The checked enumerable: ["A", "B", "C"] (3 items)
  • The expected value(s): ["A", "B", "C"] (3 items)

Conclusion

NFluent is a great asset when building Unit Tests. Using it will enhance your productivity and make your tests human readable. This is especially important when applying TDD approaches and/or Agile methodologies, where the testing code might become some sort of documentation.

There are still some possibilities of amelioration though. When checking your testing code the first error will stop the processing at the moment, which might slow down productivity. It would be better to recover a list of all detected violations to be able to fix them later in a single step.

If you chain your tests like this, the first violation will stop the processing :

image

If you want to play with NFluent or see how it has been implemented you can access its GIT repository. You may use NuGet to include it into your projects. It is available under an open-source license, so please try t for yourself and let me know what you think !


Share/Save/Bookmark

3 comments:

Anonymous said...

it seems redundant to me. its a layer on top of a testing framework. a good developer should know what assert is for even for just tracing purposes. definitely redundant for me but may serve a purpose for others.

Jason De Oliveira said...

It provides a good abstraction and makes unit tests easier to write and to understand, so I do not think that it is redundant.

Think about how .NET has streamlined Parallel Programming and Async Programming in its latest versions. You can definitely do it without using the new features but they are a great help to speed up development and to help less experienced developers to quickly have great results.

I respect your opinion but I like NFluent and the benefits it provides.

What do the other reader think ?

Rui said...

to @anonymous, when someone start a quote by "a good developer should know ...", it is usually a sign of
doubtful experience...

Everything that adds sense and clearness enhances your code! but maybe you add some comments to make things clearer ? maybe you never work with legacy code and/or with poor meaningful test? maybe you always refactor your tests to make them so simple that they don't need business meaning? in such a case, I'm really interested in seeing a gist of that kind of code! (really, not joking)