LP on .NET

August 14, 2011

Writing Testable Code

Filed under: .NET,C#,Software Development — Larry Parker @ 5:59 pm

About a year ago, my idea of unit testing included anything that could be tested no matter how heavy the setup.  This included having an available test database, available web services, and other external resources (like the file system) that were needed to test my code.

While this kind of test environment is useful, it’s more along the lines of an integrated test environment that QA would have set up.  Test likes these can really be categorized as integration tests and not unit tests.

If you want to really unit test your code, you don’t want any of the aforementioned dependencies to be part of your tests.  Unit tests should be fast and should just test a single piece of code – not your entire application’s runtime environment.

Let’s take a look at both of these approaches.  Consider the following code that registers a user with your application:

public class UserManager 
{
    public Boolean RegisterUser(String lastName, String firstName, String emailAddress)
    {
        try 
        {
            String connString = "...";

            using (var connection = new SqlConnection(connString))
            using (var cmd = new SqlCommand())
            {
                cmd.CommandText = @"
INSERT INTO User (LastName, FirstName, EmailAddress)
VALUES (@LastName, @FirstName, @EmailAddress)
";

                cmd.Parameters.Add("LastName", SqlDbType.NVarChar).Value = lastName;
                cmd.Parameters.Add("FirstName", SqlDbType.NVarChar).Value = firstName;
                cmd.Parameters.Add("EmailAddress", SqlDbType.NVarChar).Value = emailAddress;

                connection.Open();
                cmd.Connection = connection;
                cmd.ExecuteNonQuery();
            }

            return true;
        }
        catch (Exception ex)
        {
            // Log the exception... return false;
        }
    }
}

Now let’s write a test for the RegisterUser method.

[TestMethod()]
public void RegisterUserTest()
{
    UserManager target = new UserManager();
    Boolean actual = target.RegisterUser("Smith", "Bert", "bsmith@wherever.com");
    Assert.IsTrue(actual);
}

This test attempts to register a user named Bert Smith and verifies that the registration succeeded (i.e. we assert that the RegisterUser method returned true).

The test is simple enough, but in order to run it we need a database and also a User table in it.  It’s possible to set up a test database like this and ensure that the connection string is supplied for the test.  But now we have a heavy dependency that probably needs to be in a certain state every time we run the test (e.g. we probably don’t already want the user Bert Smith in the database before we run the test).

Let’s step back a second and ask ourselves exactly what we want to test in our RegisterUser test.  Do we want to test that ADO.NET works?  Hopefully Microsoft has already tested that well enough.  Do we want to test that we can write SQL that inserts a row into our User table?  At some point, but not right now.

The job of the RegisterUser method is to register a user with our system.  This probably involves some data validation (like ensuring the email address was supplied and is in a valid format), adding the user to persistent storage (like in a User table in a SQL database), and possibly sending an email to the user to let him know the registration succeeded.

All of these things are possible tasks that the RegisterUser method might need to execute, but we don’t necessarily want to test the tasks themselves – we only want to test that the tasks were called in the expected way.

Consider the email step.  How would we test that anyway?  We could use .NET’s SmtpClient class and have RegisterUser send the registration email to ourselves via our company’s email server (if we had rights to do so) and verify that we did indeed receive the email in our inbox.

The problem with this is that you need to verify that the email arrived in your inbox by looking at your inbox.  But when you run this test along with hundreds of other tests, you are not going to do this.  And neither is an automated test system.

So how do we write our RegisterUser test so we can test what we need without having all of these external dependencies?

The answer is:  dependency injection.

Dependency injection is a pattern whereby dependencies are supplied (or injected) into a system.  There are plenty of discussions about this (Martin Fowler, Wikipedia, etc.), but in a nutshell you simply hand the dependencies (typically as interfaces) to your class or method which then works with them in an abstract way.  In other words, instead of working directly with ADO.NET, your method works with an interface responsible for adding the user to persistent storage.

Let’s revisit the RegisterUser method with a couple of dependencies injected into the UserManager class’s constructor.

public class UserManager 
{
    public UserManager(IUserPersistence userPersistence, IEmailManager emailManager)
    {
        _userPersistence = userPersistence;
        _emailManager = emailManager;
    }

    private IUserPersistence _userPersistence;
    private IEmailManager _emailManager;

    public Boolean RegisterUser(String lastName, String firstName, String emailAddress)
    {
        try 
        {
            Boolean result = false;

            if (_userPersistence.AddUser(lastName, firstName, emailAddress))
                result = _emailManager.SendUserRegistrationEmail(lastName, firstName,
                    emailAddress);

            return result;
        }
        catch (Exception ex)
        {
            // Log the exception... return false;
        }
    }
}

Notice that our constructor takes two parameters that are interfaces that define our tasks.

public interface IUserPersistence 
{
    Boolean AddUser(String lastName, String firstName, String emailAddress);
    // Other interface members... 
}

public interface IEmailManager 
{
    Boolean SendUserRegistrationEmail(String lastName, String firstName, String emailAddress);
    // Other interface members... 
}

As for the RegisterUser method, what happened to the SQL that will add the user to the User table in our database?  The short answer is, “Who cares?”

Persisting the user to the database is now farmed out to an interface called IUserPersistence that has a method called AddUser.  The SQL will probably be in there, but as far as the RegisterUser method is concerned, it doesn’t care.  Our RegisterUser method just works with the interfaces:

        if (_userPersistence.AddUser(lastName, firstName, emailAddress))
            result = _emailManager.SendUserRegistrationEmail(lastName, firstName,
                emailAddress);

This is dependency injection at work.  Our code is now testable and our test can now inject dependencies into the UserManager class without having to have a database and email server set up to run the test!

Let’s rewrite our test and inject some home-grown dependencies.

public class UserPersistenceStub : IUserPersistence 
{
    public Boolean AddUser(String lastName, String firstName,
        String emailAddress)
    {
        return true;
    }
}

public class EmailManagerStub : IEmailManager 
{
    public Boolean SendUserRegistrationEmail(String lastName, String firstName,
        String emailAddress)
    {
        return true;
    }
}

[TestMethod()]
public void RegisterUserTest()
{
    var userPersistenceStub = new UserPersistenceStub();
    var emailManagerStub = new EmailManagerStub();

    UserManager target = new UserManager(userPersistenceStub, emailManagerStub);
    Boolean actual = target.RegisterUser("Smith", "Bert", "bsmith@wherever.com");
    Assert.IsTrue(actual);
}

We simply created two stub classes that implement our interfaces and then injected instances of those classes into our UserManager instance.

Now our test runs without the need for a database or an email server.  We were able to achieve this because we rewrote our UserManager class and RegisterUser method as testable code using dependency injection.

Our unit test can be improved (e.g. by using tools like Moq), but I will save that for another post.  For now, the main takeaway of this post is that code can be written to be testable using dependency injection.

It took me a while to realize the importance of writing testable code.  The fact that testable code can be unit tested without needing external resources like databases opens up the door to writing a slew of tests to thoroughly test your code, and this gets you into the area of code coverage and even test-driven development.

More to come on this…

Advertisements

4 Comments »

  1. […] this new approach, our RegisterUser method from our previous post now looks like […]

    Pingback by Dependency Injection and Delegates « LP on .NET — August 29, 2011 @ 10:47 pm | Reply

  2. […] the last year or so, you may have noticed that I discussed certain aspects of unit testing (like writing testable code and unit testing using stubs) but haven’t mentioned much about mocking […]

    Pingback by Introduction to Unit Testing with Moq « LP on .NET — January 2, 2012 @ 1:32 pm | Reply

  3. This is very well written. Thank you!

    Comment by New Tester — March 26, 2013 @ 9:53 am | Reply

  4. […] The common denominator to all this has been dependency injection.  To quote myself from a previous post: […]

    Pingback by Dependency Injection – A Compromise | LP on .NET — April 3, 2013 @ 9:38 pm | Reply


RSS feed for comments on this post. TrackBack URI

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

Create a free website or blog at WordPress.com.

%d bloggers like this: