Unit testing

Everyone knows unit testing is an important but often forgotten part of software development. I’ve been there where it seems to be more convenient to leave out unit tests because we don’t have enough time to unit test a function or i tmight be just a bit too annoying to mock up some services to unit tests. However, over the years, I’ve grown to appreciate unit tests and what they do as it can help us avoid unnecessary bugs that can occur when we inadvertently edit a function and change the way it’s supposed to work.

NUnit and Moq

In order to run unit tests, we need to be able to use a unit testing framework. Te one I’ve been using is NUnit and we’ll be focusing on using that for the purpose of this post. In addition to NUnit, we’ll also need Moq, a mocking framework, that will be used to help us mock services for unit testing.

While I’ll cover more unit tests posts in the future, this particular post will be kept abridged by focusing on the different ways we can asshert that an argument provided to a method can be checked.

Sample services

Let’s have the following class in place:

public class NotificationService {

    public NotificationService()

    public void NotifyUser(User user) { 
        if (user.NeedsNotification) { 
            _emailService.Notify(user);
        }
    }
}

With the above service, there’s a really simple if statement that needs to be run if a user needs to be notified. A couple of tests that comes to my mind right away is to ensure that _emailService.Notify() is called for the user once if the user needs to be notified.

The test project

Let’s create a test project and have a method to test the service above. We’ll go through the different ways we can check the user argument that is being passed into the _emailService.

[Test]
public void Ensure_NotifyUser_sends_email_when_user_needs_notification()
{
    // Arrange
    User userToAssert = null;

    _mockEmailService.Setup(x => x.SendEmail(It.IsAny<User>()))
        .Callback<User>(y => userToAssert = y);

    // Act
    var userToCheck = new User() { FirstName = "Samuel", NeedsNotification = true };
    _serviceToTest.NotifyUser(userToCheck);

    //Assert
    _mockEmailService.Verify(x=> x.SendEmail(It.IsAny<User>()), Times.Once, "A user that needs notification should be emailed");
    
    // First way of verifying the properties in the user
    _mockEmailService.Verify(x=> x.SendEmail(It.Is<User>(u => u.NeedsNotification == true && u.FirstName == "Samuel")));

    // Second way of verifying the properties in the user
    Assert.True(userToAssert.NeedsNotification);
    Assert.AreEqual("Samuel", userToAssert.FirstName);

}

)

Verifying the user using the Verify() method

// First way of verifying the properties in the user
_mockEmailService.Verify(x=> x.SendEmail(It.Is<User>(u => u.NeedsNotification == true && u.FirstName == "Samuel")));

This would be the simplest way to check the argument that is being passed into the method. I would use this verify() method if I know it’s a simple check and perhaps we don’t need to check more than a couple of properties in the argument. It’s clean if we are only checking a couple of properties but once we need to check more properties, it can become quite convoluted.

Setting up a callback earlier to assign the user

User userToAssert = null;

_mockEmailService.Setup(x => x.SendEmail(It.IsAny<User>()))
    .Callback<User>(y => userToAssert = y);

The second approach we can take into checking the arguments is to assign a callback. The Callback() method allows us to set the userToAssert value to the user argument that’s passed into the SendEmail() method. When SendEmail() is called, we then set the value of userToAssert to whatever has been passed in. From there, we’ll be able to Assert properties that we need to assert.

I feel that this might be a clenaer approach when the property that needs to be checked is complicated.

Conclusion

We’ve just gone over two approaches on how to validate incoming arguments to a method using NUnit and Moq. I prefer to use the verify() method when we don’t need to check complicated models as this would not require an extra setup with callback line. However, if the model that needs to be checked is quite complicated, it feels cleaner to me to just use the callback approach.

Github

Unit test source code