By this point in the series, you should know quite a bit about the basics of unit testing in .NET.  You should be able to write unit tests using NUnit, and you (hopefully) understand the value that unit testing brings to the table.  As you’ve started to apply what you’ve learned though (and you are applying what you’ve learned, riiiiight?), you might have run into things that were difficult to create test cases for.  Worse yet, maybe you ran into things that you couldn’t test at all.  Fret not, as post 4 in this series is here to save the day.  In this post, we’ll look at some of the basic testing problems that you are likely to encounter and how to overcome them.  Let’s get started:

Classes with complicated setup

First, some classes require complicated setup or configuration before they’re testable.  If you have multiple test cases for your class, you could end up with that setup code repeated in a lot of places.  Having to rewrite all that code is painful, and it will probably make you cut corners to keep your number of test cases low.  Even if it doesn’t, what happens if the setup or configuration steps for the class change?  Now you have to change that code in a lot of places. 

The solution is simple: Don’t Repeat Yourself (aka the DRY principle).  DON’T repeat the configuration or setup code.  Encapsulate it instead.  Some people choose to make a field in the test fixture for the class-under-test (the class we’re creating unit tests for), then use a test case setup method to populate the instance for each test case like so:

   1: [TestFixture]
   2: public class ComplicatedClassTests
   3: {
   4:     private ComplicatedClass mInstance;
   5:  
   6:     [SetUp]
   7:     public void TestSetup()
   8:     {
   9:         mInstance = new ComplicatedClass("http://localhost/testApp", new Random(), new OtherDependency(), "name", 12345);
  10:         mInstance.EnableNotifcations();
  11:         mInstance.SomeOtherSetup();
  12:     }
  13:  
  14:     [Test]
  15:     public void Operation_ReturnsTrue()
  16:     {
  17:         Assert.IsTrue(mInstance.Operation());
  18:     }
  19: }

As a matter of personal preference, I tend to avoid this approach.  What happens when you have a test case that needs to configure the class-under-test a little differently than usual?  You could just reset ignore the private field and make a local instance, but that private field has still been instantiated.  Is it hurting anything?  No, probably not, but it’s still there, and that bugs me.  Plus, I don’t like test fixtures having state, which is exactly what a private field is.

Instead, I encapsulate the common setup logic in a private helper method that my tests can call to grab a fresh reference to the class-under-test, like so:

   1: [TestFixture]
   2: public class ComplicatedClassTests
   3: {
   4:     private ComplicatedClass GetTestInstance()
   5:     {
   6:         ComplicatedClass instance = new ComplicatedClass("http://localhost/testApp", new Random(), new OtherDependency(), "name", 12345);
   7:         instance.EnableNotifcations();
   8:         instance.SomeOtherSetup();
   9:  
  10:         return instance;
  11:     }
  12:  
  13:     [Test]
  14:     public void Operation_ReturnsTrue()
  15:     {
  16:         ComplicatedClass instance = GetTestInstance();
  17:         Assert.IsTrue(instance.Operation());
  18:     }
  19: }

If the test case just needs an instance with the default configuration, it can call the helper method, otherwise, it can perform it’s own setup and configuration.  Yes, you are technically repeating yourself since many of the test cases will have a line of code to retrieve the class-under-test, but DRY is more of a guideline than an actual rule. 😛

Addendum: One time when I will go the test setup route is when the class-under-test also requires some special cleanup.  While this should be avoided if at all possible, sometimes it’s necessary.  In those cases, I will use a test setup method combined with a test tear-down method.

Tight Coupling

In a perfect world, all your classes would be fully self-contained and would have no dependencies on other classes, making it very easy to create unit tests that only stress the class-under-test.  In the real world though, this almost never happens.  Depending on what the class-under-test is dependent on, this can be a real problem.  Suppose your class makes calls into some other class, and suppose those calls are expensive (on the order of minutes).   Suppose that you already have thorough unit tests for that other class.  Well, your test cases for the class-under-test are going to take a long time to run, and they’re going to exercise already tested code.  What can you do?  Let’s take a look at the original class:

   1: public class ComplicatedClass
   2: {
   3:     private LongRunningService mHelper;
   4:  
   5:     public ComplicatedClass()
   6:     {
   7:         mHelper = new LongRunningService();
   8:     }
   9:  
  10:     public void SimpleMethod()
  11:     {
  12:         Console.WriteLine("Beginning long running operation, this may take a while...");
  13:         mHelper.DoSomething();
  14:     }
  15: }

My recommendation is to use interfaces everywhere, and apply Dependency Injection.  When you apply Dependency Injection, the instantiator of your class becomes responsible for specifying which concrete dependencies to use.  When you combine this with interfaces, it becomes quite easy to mock access to external classes.  Here’s our code, but modified so that we can apply Dependency Injection:

   1: public class DependentClass
   2:     {
   3:         private IService mHelper;
   4:  
   5:         public DependentClass()
   6:             : this(new LongRunningService())
   7:         {
   8:         }
   9:  
  10:         public DependentClass(IService helper)
  11:         {
  12:             mHelper = helper;
  13:         }
  14:  
  15:         public void SimpleMethod()
  16:         {
  17:             Console.WriteLine("Beginning long running operation, this may take a while...");
  18:             mHelper.DoSomething();
  19:         }
  20:     }
  21:  
  22:     public interface IService
  23:     {
  24:         void DoSomething();
  25:     }
  26:  
  27:     public class LongRunningService : IService
  28:     {
  29:         public void DoSomething()
  30:         {
  31:             Thread.Sleep(TimeSpan.FromSeconds(10));
  32:         }
  33:     }

To test the class without exercising LongRunningService, we create a private class that implements the IService interface, and pass that in through our unit tests, like so:

   1: private class TestService : IService
   2: {
   3:     public void DoSomething()
   4:     {
   5:         Console.WriteLine("In mock class!");
   6:     }
   7: }
   8:  
   9: [Test]
  10: public void SimpleMethod_DoesntExplode()
  11: {
  12:     DependentClass instance = new DependentClass(new TestService());
  13:     instance.SimpleMethod();
  14:  
  15: }

Notice how I’ve given DependentClass a default constructor that takes care of instantiating the "real" concrete implementation.  While this approach works, a more robust solution is to use an Inversion of Control Container, which we might explore in a future post.

Error-Handling Logic

A related testing problem is error-handling logic.  Error-handling logic for method parameters is quite easy to test (just pass in a bogus parameter from your test), but simulating error handling around an external resource, such as a web service, is much more difficult.  Let’s take a look at a method from our old friend, the Account class:

   1: /// <summary>
   2: /// Transfers money to the specified account.
   3: /// </summary>
   4: /// <param name="targetAccount"></param>
   5: /// <param name="amount"></param>
   6: /// <returns></returns>
   7: public bool TransferMoney(int targetAccount, double amount)
   8: {
   9:     AccountService service = new AccountService("http://partner.bank/Management.asmx");
  10:  
  11:     if (!service.Transfer(targetAccount, amount))
  12:     {
  13:         Console.WriteLine("Failed to transfer!");
  14:         //TODO: Put additional error-handling logic here
  15:         return false;
  16:     }
  17:     else
  18:     {
  19:         return true;
  20:     }
  21: }
  22:  

How can we force our web service to fail so that we can verify our error-handling logic?  Well, we could have our test disable the network card in the machine or something like that, but there’s an easier way.  Again, by using interfaces and dependency injection, we can easily simulate whatever error we desire. 

   1: public class Account : ICloneable
   2: {
   3:     ...
   4:     /// <summary>
   5:     /// The account service.
   6:     /// </summary>
   7:     private IAccountService mService;
   8:  
   9:     /// <summary>
  10:     /// Creates an account that will use the default service.
  11:     /// </summary>
  12:     public Account() : this(new AccountService("http://partner.bank/Management.asmx"))
  13:     {
  14:         
  15:     }
  16:  
  17:     /// <summary>
  18:     /// Creates an account that will use the specified service.
  19:     /// </summary>
  20:     /// <param name="service"></param>
  21:     public Account(IAccountService service)
  22:     {
  23:         mService = service;
  24:     }    
  25:     
  26:     /// <summary>
  27:     /// Transfers money to the specified account.
  28:     /// </summary>
  29:     /// <param name="targetAccount"></param>
  30:     /// <param name="amount"></param>
  31:     /// <returns></returns>
  32:     public bool TransferMoney(int targetAccount, double amount)
  33:     {
  34:         if (!mService.Transfer(targetAccount, amount))
  35:         {
  36:             Console.WriteLine("Failed to transfer!");
  37:             //TODO: Put additional error-handling logic here
  38:             return false;
  39:         }
  40:         else
  41:         {
  42:             return true;
  43:         }
  44:     }
  45:     
  46:     ...
  47: }
  48:  
  49: /// <summary>
  50: /// Interface that account services implement.
  51: /// </summary>
  52: public interface IAccountService
  53: {
  54:     bool Transfer(int account, double amount);
  55: }
  56:  
  57: /// <summary>
  58: /// The real account service.
  59: /// </summary>
  60: public class AccountService : IAccountService
  61: {
  62:     /// <summary>
  63:     /// .
  64:     /// </summary>
  65:     /// <param name="url"></param>
  66:     public AccountService(string url)
  67:     {
  68:         //TODO: real web service logic goes here.
  69:     }
  70:  
  71:     /// <summary>
  72:     /// .
  73:     /// </summary>
  74:     /// <param name="account"></param>
  75:     /// <param name="amount"></param>
  76:     /// <returns></returns>
  77:     public bool Transfer(int account, double amount)
  78:     {
  79:         //TODO: real webservice logic goes here.
  80:         return true;
  81:     }
  82: }

With the refactoring in place, all we have to do is create a test class that implements that interface, then pass that test object in to our class-under-test, like so:

   1: /// <summary>
   2: /// Used to facilitate testing of error-handling logic.
   3: /// </summary>
   4: private class TestAccountService : IAccountService
   5: {
   6:     /// <summary>
   7:     /// Simulates a bad transfer.
   8:     /// </summary>
   9:     /// <param name="account"></param>
  10:     /// <param name="amount"></param>
  11:     /// <returns></returns>
  12:     public bool Transfer(int account, double amount)
  13:     {
  14:         return false;
  15:     }
  16: }
  17:  
  18: /// <summary>
  19: /// Verifies that the method returns false if it can't communicate
  20: /// with the remote account service.
  21: /// </summary>
  22: [Test]
  23: public void Transfer_ReturnsFalseIfCommunicationFails()
  24: {
  25:     Account account = new Account(new TestAccountService());
  26: }

Sealed Dependencies

Dependency injection and interface-driven design can make testing simpler and save you a lot of headaches, but there are times when applying it may not seem so obvious.  Let’s look at an example class that takes in log messages and sends an E-mail if the log looks like an error:

   1: /// <summary>
   2: /// Inspects log messages and sends E-mails if an error occurs.
   3: /// </summary>
   4: public class LogMonitor
   5: {
   6:     /// <summary>
   7:     /// Inspects log messages, and sends an E-mail if a message
   8:     /// contains the word "error".
   9:     /// </summary>
  10:     /// <param name="message"></param>
  11:     public void InspectLogMessage(string message)
  12:     {
  13:         if (message.ToUpper().Contains("ERROR"))
  14:         {
  15:             SmtpClient client = new SmtpClient();
  16:             client.Send("[email protected]", "[email protected]", "Error!", message);
  17:         }
  18:     }
  19: }

To fully test this class, we need to verify that an E-mail is sent when an error message is passed in.  SmtpClient is a sealed class that we don’t have access to, and it doesn’t have an interface, so we can’t directly apply dependency injection.  Fortunately, there is a simple pattern we can apply to solve our problem: the Adapter Pattern.  First, we create an interface that abstracts the parts of SmtpClient that our application uses, like so:

   1: /// <summary>
   2: /// Wrapper interface for <see cref="SmtpClient"/>.
   3: /// </summary>
   4: public interface ISmtpClient
   5: {
   6:     /// <summary>
   7:     /// Sends an E-mail.
   8:     /// </summary>
   9:     /// <param name="from"></param>
  10:     /// <param name="recipients"></param>
  11:     /// <param name="subject"></param>
  12:     /// <param name="body"></param>
  13:     void Send(string from, string recipients, string subject, string body);
  14: }

Next, we create an adapter class that wraps SmtpClient into our interface:

   1: /// <summary>
   2: /// Adapts <see cref="SmtpClient"/> into the <see cref="ISmtpClient"/>
   3: /// interface.
   4: /// </summary>
   5: public class SmtpClientAdapter : ISmtpClient
   6: {
   7:     /// <summary>
   8:     /// Sends an E-mail.
   9:     /// </summary>
  10:     /// <param name="from"></param>
  11:     /// <param name="recipients"></param>
  12:     /// <param name="subject"></param>
  13:     /// <param name="body"></param>
  14:     public void Send(string from, string recipients, string subject, string body)
  15:     {
  16:         SmtpClient client = new SmtpClient();
  17:         client.Send(from, recipients, subject, body);
  18:     }
  19: }

Finally, we apply dependency injection to our class-under-test, and update our test cases, passing in a mock that we can use to verify that a mail message was "sent".

LogMonitor:

   1: /// <summary>
   2: /// Inspects log messages and sends E-mails if an error occurs.
   3: /// </summary>
   4: public class LogMonitor
   5: {
   6:     /// <summary>
   7:     /// The client used to send E-mail
   8:     /// </summary>
   9:     private ISmtpClient mClient;
  10:  
  11:     /// <summary>
  12:     /// Creates a monitor that will use the default SMTP client.
  13:     /// </summary>
  14:     public LogMonitor() : this(new SmtpClientAdapter())
  15:     {
  16:         
  17:     }
  18:  
  19:     /// <summary>
  20:     /// Creates a monitor that will use the specified 
  21:     /// <see cref="ISmtpClient"/>.
  22:     /// </summary>
  23:     /// <param name="smtpClient"></param>
  24:     public LogMonitor(ISmtpClient smtpClient)
  25:     {
  26:         mClient = smtpClient;
  27:     }
  28:  
  29:     /// <summary>
  30:     /// Inspects log messages, and sends an E-mail if a message
  31:     /// contains the word "error".
  32:     /// </summary>
  33:     /// <param name="message"></param>
  34:     public void InspectLogMessage(string message)
  35:     {
  36:         if (message.ToUpper().Contains("ERROR"))
  37:         {
  38:             mClient.Send("[email protected]", "[email protected]", "Error!", message);
  39:         }
  40:     }
  41: }

And LogMonitorTests:

   1: /// <summary>
   2: /// Tests fixture for <see cref="LogMonitor"/>.
   3: /// </summary>
   4: [TestFixture]
   5: public class LogMonitorTests
   6: {
   7:     /// <summary>
   8:     /// Test class.
   9:     /// </summary>
  10:     private class TestSmtpClient : ISmtpClient
  11:     {
  12:         /// <summary>
  13:         /// Incremented every time a message is sent.
  14:         /// </summary>
  15:         public int MessagesSent { get; private set; }
  16:  
  17:         /// <summary>
  18:         /// Records that a message was sent.
  19:         /// </summary>
  20:         /// <param name="from"></param>
  21:         /// <param name="recipients"></param>
  22:         /// <param name="subject"></param>
  23:         /// <param name="body"></param>
  24:         public void Send(string from, string recipients, string subject, string body)
  25:         {
  26:             Console.WriteLine("Received message: {0}", body);
  27:             MessagesSent++;
  28:         }
  29:     }
  30:  
  31:     /// <summary>
  32:     /// Verifies that the method correctly sends an E-mail 
  33:     /// when it receives an error log.
  34:     /// </summary>
  35:     [Test]
  36:     public void InspectLogMessage_SendsErrorEmail()
  37:     {
  38:         TestSmtpClient client = new TestSmtpClient();
  39:  
  40:         LogMonitor monitor = new LogMonitor(client);
  41:  
  42:         monitor.InspectLogMessage("This is an error.");
  43:  
  44:         Assert.AreEqual(1, client.MessagesSent);
  45:     }
  46: }

Database Access Code

The mother of all external dependencies is database access code.  How do you test code that must interact with a database?  In some cases, we can apply what we’ve learned (dependency injection, the adapter pattern, etc), but those solutions won’t scale well to a complicated system with a lot of data access logic, and if you are trying to mock classes from the System.Data.Sql namespace, You Are Doing It Wrong.  You can’t just let your classes-under-test access the real database, either, because that’s a shared resource; changes made in one test will be visible in another, a clear violation of the principles of unit testing.  Using a real database heavily in your unit tests will also guarantee that your tests will take forever to run.  Remember that unit tests should execute quickly (and consistently), so that approach is not viable.

Unfortunately, I have yet to find a good solution to this problem.  I have taken two approaches in the past, both of which have some downsides.  One approach was to wrap all data access code in an interface.  We then created two classes that implemented that interface: one was real (it actually talked to SQL Server), and the other was a horrible mess of code that was basically an in-memory database.  Aside from having to maintain a complex code base to facilitate testing (our in-memory version is about as many lines of code as our real SQL version), developing and testing against the in-memory version led to a lot of problems.  The in-memory version didn’t always enforce the same constraints that the real version would, so we would frequently run into things that worked fine in testing but failed in production. 

If you are using an ORM, your options are slightly better.  With Castle ActiveRecord or NHibernate, you can use SQLite, and you get mostly equivalent functionality to a real SQL Server database.  You also have less code to test since most of the common CRUD stuff has been done for you.  This approach can be problematic to setup and maintain, but it’s the best solution I’ve found so far.  You can find out more about how to set that up with ActiveRecord in my post on Easy testing via ActiveRecord and SQLite.

GUIs

Finally, one of the most commonly asked unit testing question is "how do I unit test my GUI?"  My answer is "you don’t."  Your code should be structured so that the code-behind for your GUI contains a *minimal* amount of logic.  Regardless of whether we’re talking WinForms or WebForms, your GUI should contain only the logic dealing specifically with presentation (layout and formatting), and nothing more.  Anything beyond that should go into "middle tier" classes, classes that can easily be tested.  Here’s an example for a BAD event handler:

   1: private void OrderButton_Clicked(object sender, EventArgs e)
   2: {
   3:     string item = ItemTextBox.Text;
   4:     int quantity = int.Parse(QuantityTextBox.Text);
   5:  
   6:     SqlConnection connection = new SqlConnection(mConnectionString);
   7:  
   8:     SqlCommand command = new SqlCommand("INSERT INTO Orders(Item,Quantity) VALUES(@Item,@Quantity)", connection);
   9:     command.Parameters.AddWithValue("Item", item);
  10:     command.Parameters.AddWithValue("Quantity", quantity);
  11:  
  12:     connection.Open();
  13:  
  14:     int resultCount = command.ExecuteNonQuery();
  15:  
  16:     if (resultCount == 0)
  17:     {
  18:         ResultLabel.Text = "No rows were inserted!";
  19:     }
  20:     else
  21:     {
  22:         ResultLabel.Text = "Database updated!";
  23:     }
  24: }

And here’s what the event handler looks like once you’ve refactored it:

   1: private void OrderButton_Clicked(object sender, EventArgs e)
   2: {
   3:     OrderProcessor processor = new OrderProcessor();
   4:  
   5:     if (!processor.HandleNewOrder(ItemTextBox.Text, QuantityTextBox.Text))
   6:     {
   7:         ResultLabel.Text = "No rows were inserted!";
   8:     }
   9:     else
  10:     {
  11:         ResultLabel.Text = "Database updated!";
  12:     }
  13: }

If you absolutely HAVE to write test cases for a GUI, there are toolkits that can help.  I have very little/no experience with these, so use at your own risk (and remember, good design is a almost always a better answer):

If you have experience with any of these tools, please chime in below and let myself and others know what you think of them.

Up Next…

In today’s post, I’ve gone through some of the commonly-encountered unit testing problems, and I’ve hopefully shown you how to address them.  In the next post, we’ll look at how to take make it easier to apply dependency injection and the adapter pattern through the use of the excellent Moq mocking framework.  Look for that post on Friday at the earliest.