Unit Testing 101: Basics

Introduction

We all know unit testing is an essential part of the development cycle. Actually, unit tests code is as important as the actual application code (Yeap, you read that right); this is something we should never forget. That’s why we are going to look at some important (introductory) concepts relating to composing proper testing code.

I will be using NUnit as my testing library. The package comes with the framework libraries and a set of test runner clients. You can download it at their site’s download section.

Unit Test Structure

Unit tests are usually grouped in test fixtures. Basically, a test fixture is a group of unit tests targeted to verify a single application feature. Let’s illustrate this in code:

using NUnit.Framework;

namespace AppDemo.Tests
{
    [TestFixture(Category = "User Authentication")]
    public class WhenUserIsBeingAuthenticated
    {
        [Test]
        public void ShouldReturnTrueIfValidationIsSuccessful()
        {
            // TODO: Implement test code.
        }

        [Test]
        public void ShouldReturnFalseIfUsernameOrPasswordIsNull()
        {
            // TODO: Implement test code.
        }
    }
}

We can now picture how a test fixture looks in code. In this case, the test fixture is a regular class filled out with test methods. As you might have noticed, the class name describes the state of the feature being tested: “When the user is being authenticated”. Each particular test method seeks to verify a required result on a specific condition: “Should return true if validation is successful”.

Running Tests

Once you have your fixture ready to go, is now time to run all tests on it and see results. I will be using the NUnit GUI Runner which looks for all classes in the assembly marked with the [TestFixture] attribute and then calls each method on them marked with the [Test] attribute. Is important to remember that all tests must be in a separate class library. First reason is because it is a good practice, you should not be mixing application code with test code; and second because the NUnit test runner can only load DLL files.

So, first thing to do is to build the project so we have a DLL containing all our tests. Once we have a DLL file with our test fixture classes on it, fire up the NUnit test runner (NUnit.exe) and load the file on it.

NUnit Test Runner

At this point everything is quite intuitive. You can hit the “Run” button and see how all tests pass or rebuild the project on Visual Studio and see how the test runner auto-updates with new changes. Cool, huh?

Arrange, Act and Assert

Test methods are usually composed of three common phases: Arrange, act and assert. Or “triple-A” if you like.

  • Arrange: At the very beginning of the method, you need to setup the test scenario. This includes expected test results for comparison with actual results, instances of the components to be tested and type mocking.
  • Act: After arrangement is done, we now have to actually perform the actions that will produce the actual test results. For instance, call the Validate method on the UserAuthenticator class which performs the actual user validation.
  • Assert: The assertion phase verifies that actual tests results match what we are expecting.

Is a good practice to provide comments delimiting each phase:

[Test]
public void ShouldReturnTrueValidationIsSuccessful()
{
    // Arrange
    var expectedResult = true;
    var userAuthenticator = new UserAuthenticator();

    // Act
    var actualResult = userAuthenticator.Validate("luis.aguilar", "1234");

    // Assert
    Assert.That(actualResult, Is.EqualTo(expectedResult), message = "Authentication failed though it should have succeeded.");
}

As you might see, these three phases are executed in order. Is a good practice to initialize variables with expected results at Arrange phase to make the Assert phase more readable. Also, for the sake of readability, I am using the Assert.That syntax of NUnit so assertions are more verbose.

Tests Before Implementation

Even though unit testing is good for all development methodologies, I’m an avid supporter of the Test-Driven-Development (TDD) methodology. As the name implies, TDD is all about writing all tests BEFORE you implement actual application code. That way, your code will meet acceptance criteria right from inception. Basically, application infrastructure design is driven by tests. Now we think on user requirements rather than UML diagrams and classes.

For instance, you should write all the previous sample tests before implementing the UserAuthenticator class. That way that particular class will be born satisfying user requirements so we don’t have to  change its code later on, which helps save lots of time (and money, managers love to hear that) and improves code efficiency and design greatly.

Conclusion

Okay, hopefully this served out as a brief introduction to the exciting world of unit testing. Of course, there’s a lot more on this topic. In next articles we are going to look at concepts like inversion of control, type mocking and more things related to TDD. Is going to be lots of fun!

Stay tuned! 😉

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

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