What is unit testing? Dependency injection?

Previously, I mentioned that dependency injection is important for unit testing. If you are unfamiliar with either of these concepts, then your eyes probably glossed over when you read that sentence. I’m sure you could find many articles that cover unit testing and dependency injection on the interwebs. However, since I try to be newbie friendly (i.e. I am a newbie), I’m going to try to explain – in layman’s terms – the basic ideas behind these concepts. This will also give me a chance to learn more by teaching, which is how I learn best.

NOTE: I won’t be discussing test-driven development here. Some beginners get unit testing and TDD confused, but TDD is a separate topic that deserves its own article at some point in the future.

Unit testing

If you’ve ever done any programming in any language, then you are already familiar with manual testing. You might call it “looking for bugs” or “checking your work,” but it all boils down to launching your software and using it. At first, manual testing is quick and easy. After creating an HTML page, for instance, you would open it in a browser to verify that it looks okay. If it doesn’t, you would have to adjust the HTML until it passes the test. If it does, you might create another page and repeat the process. After that, you would need to add links from each page to the other. Then, you would have to open each page in a browser to verify that the links on each page work.

Here’s what usually happens pretty quickly: you have several pages, each with links to several other pages. Then, without thinking through the ramifications, you change a file name. This tends to happen at the worst possible moments, like right after your pages go live. Of course, it’s possible to test every link on every page every time you make a change like that. But if you are working on a large project, it can become extremely time consuming. Wouldn’t it be nice if there was a way to test every link on every page automatically every time you make a change?

There is a way. It’s called unit testing, and – if implemented correctly – it will save you from breaking changes. The reason it’s called unit testing instead of automatic testing is because it normally involves testing a single unit of code (a method or an action) at a time. To be honest, I don’t have a clue how you would write a unit test for the above scenario – at least not if all we’re dealing with is simple HTML pages. Frameworks such as Zend for PHP and ASP.NET MVC for C# lend themselves to such cases, which is one reason why they’re so popular. Here’s how we might do it in C#:

public class MyTests
{
    public void TestLinks()
    {
        // Arrange
        var links = GetAllLinks();
        var numErrors = 0;

        // Act
        foreach (var link in links)
        {
            if (!TryLink( link ))
            {
                numErrors ++;
            }
        }

        // Assert
        Assert.AreEqual( 0, numErrors );
    }
}

Of course, the implementation of such a test will vary greatly depending on the framework. Arrange-Act-Assert is a common pattern for unit testing:

  1. Arrange: Set up any variables that will be used in the test
  2. Act: Call the method or execute the action to be tested
  3. Assert: Check that the conditions of the test were met

At the end of the TestLinks method above, we assert that the number of errors is equal to zero. If it’s not, then the test will fail, letting us know that a link is broken. Ideally, you would run this test after making any changes that could affect it. Most importantly, you would run it before committing those changes to source control.

Dependency injection

Dependency injection is often associated with unit testing because it allows you to test a unit of code by passing in a fake implementation rather than a concrete object. The most obvious case where you would want use this is to test a unit of code that needs to save data to a database.

Imagine that, on your website, a user can sign up for an account. To do this, the user must fill out and submit a form, which inserts a record into the database. This is something that needs to be tested – extensively, in fact, if you are a good developer.

If you’re using a data layer such as NHibernate or Entity Framework, you don’t need to test that the data is inserted into the database correctly. Also, you don’t want to insert a bunch of dummy data into the database. Instead, you need to test that the form is submitted, that an account is created, and that the page is redirected. If the user forgets to fill out a required field on the form, the page should be redirected to an error page, or back to the same page so the user can try again.

Now, assume your user controller has an action called NewUser that handles the form submission. In ASP.NET MVC, it might look something like this:

public class UserController : Controller
{
    [HttpPost]
    public ActionResult NewUser( User user )
    {
        // Data validation goes here
        // ...

        // Create a new instance of the repository
        var db = new Database();

        // Insert the record into the database
        db.Save( user );

        // Redirect the user to the success page
        return Redirect( Success );
    }
}

Then, our unit test might look something like this:

public void TestNewUser()
{
    // Arrange
    var controller = new UserController();
    var user = new User
    {
        FirstName = "Dave",
        LastName = "Ryder",
        UserName = "BigMcLargeHuge1",
        Password = "12345"
    };

    // Act
    var result = controller.NewUser( user );

    // Assert
    Assert.AreEqual( "Success", result.RouteData["Action"] );
}

Running that test would insert the dummy data into the database, but we’re not interested in that part. What we’d rather do is skip that part and just test that the page is redirected to the right action. To do that, we need to pass a fake database to the home controller:

public void TestNewUser()
{
    // Arrange
    var controller = new UserController( new Fake<Database>() );
    var user = new User
    {
        FirstName = "Dave",
        LastName = "Ryder",
        UserName = "BigMcLargeHuge1",
        Password = "12345"
    };

    // Act
    var result = controller.NewUser( user );

    // Assert
    Assert.AreEqual( "Success", result.RouteData["Action"] );
}

Then, we would need to modify the constructor of our user controller to accept a parameter for the repository. In other words, we need to inject our dependency into the constructor. We also remove the instantiation of the database class from the NewUser action:

public class UserController : Controller
{
    private readonly Database db;

    public UserController( Database db )
    {
        this.db = db;
    }

    [HttpPost]
    public ActionResult NewUser( User user )
    {
        // Data validation goes here
        // ...

        // Insert the record into the database
        db.Save( user );

        // Redirect the user to the success page
        return Redirect( Success );
    }
}

Instead of saving the data, our fake implementation of the database class just pretends to save the data so we can go on testing the parts we care about.

Conclusion

Hopefully, now you get the basic ideas behind unit testing and dependency injection. As I mentioned before, my next article will cover using NUnit and Moq for unit testing an ASP.NET MVC 3 application with NHibernate and Castle Windsor already implemented.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

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