Unit Testing with NUnit

Unit Testing with NUnit

A very short intro and comparison between the MSTest framework and the very popular NUnit framework.
For a more complete list of differences between the frameworks, see: https://xunit.github.io/docs/comparisons.html.

Getting started

Add a new project to your visual studio solution. I found 3 different ways to get started:

Make sure to name the new project “.Test(s)”. The ending in .Test or .Tests is important not only in readability but also for continuous testing environments like Team City (more on that in a later post)

But what about internals?

What if you want to test your internal classes or methods, in this separate project? You can’t access then … luckily you can with a little bit of code. In your “projectUnderTest” locate the “AssemblyInfo.cs” file and add:

[assembly:InternalsVisibleTo("projectUnderTestName.Test")]

Writing your first test

Always try to write your unit test in such a way it tests a single unit and make the test methods as concise as possible, testing only one feature of the unit.
In other words try and make your class only responsible for one thing, use dependency injection if/where possible (useful for mocking) and make not just one big test method, that has a plethora of different assert statements, testing different things/actions.

A great video on dependency injection: https://www.youtube.com/watch?v=QtDTfn8YxXg

I also highly recommend ReSharper together with dotCover, to give you some beautiful code coverage statistics and insights.

Lets say we have a customer class and we want to test this:

    public class Customer
    {
        public Customer(int id, string firstName, string lastName)
        {
            this.Id = id;
            this.FirstName = firstName;
            this.LastName = lastName;
        }

        public int Id { get; }

        public string FirstName{ get; }

        public string LastName { get; }

        public DateTime DateOfBirth { get; set; }

        public string Phone { get; set; }
    }

A very simple test class could look like this:

    [TestFixture]
    public class CustomerTests
    {
        [Test]
        public void CreateAndCheckProperties()
        {
            var customer = new Customer(1, "Olivia", "Spears")
            {
                Phone = "903-998-1869",
                DateOfBirth = new DateTime(1972, 9, 11)
            };

            Assert.That(customer.Id, Is.EqualTo(1));
            Assert.That(customer.FirstName, Is.EqualTo("Olivia"));
            Assert.That(customer.LastName, Is.EqualTo("Spears"));
            Assert.That(customer.DateOfBirth, Is.EqualTo(new DateTime(1972, 9, 11)));
            Assert.That(customer.Phone, Is.EqualTo("903-998-1869"));
        }
    }

Ok, this test will generate a code coverage of 100% but doesn’t really test much as currently the properties are just being set and then we access them again to see if the value is still the same, which will always be true. But what if we change the phone property to, when set, do some formatting …
A good movie about Test Driven Development with more examples: https://www.youtube.com/watch?v=TxGzhDYTX10.

Exceptions

Sometimes you want to test if the method you are calling throws an expected exception. In MSTest you have to decorate the test method:

    [TestMethod]
    [ExpectedException(typeof(ArgumentOutOfRangeException))]
    public void CreateAndCheckProperties()
    {...

This has 2 drawbacks for me, one I can’t seem to get my code coverage to pass this sort of test, it usually leaves me with one uncovered line. But the biggest drawback in my opinion is that I can’t tell exactly where the code should fail and this might become a readability/maintenance issue. NUnit (and XUnit) has come up with a very useful method for this:

    Assert.Throws(() => test.GetApiEntityName());

Conclusion

There is obviously a lot more to unit testing and using a test framework than what I described above, but I hope it will get you started and put you on the right track to writing your own (more useful 😉 ) tests.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.