Previously on "Unit Testing in .NET", we’ve looked at:

That means you should be comfortable with the all the fundamental concepts of software testing, and you should be equipped to deal with some common testing headaches.  In this post, we’re going to look at how to simplify testing via dependency injection and the excellent mocking library, Moq.

What is mocking?

Mocking refers to the act of substituting a simulated object in place of a real object.  In unit testing, it is quite common to use mocking to separate the class-under-test from its external dependencies, making the class much easier to fully test.  I didn’t talk much about it, but that’s exactly what we were doing in the previous post when we applied dependency injection and the adapter pattern.  We were substituting a fake object (the mock) that we had given a specific behavior to for the real object. 

Sidetrack: what’s the difference between a mock object, a fake object, and a stub?
Nothing that really matters, in my opinion.  Purists will argue the semantic differences between them, but I don’t think that’s really helpful as long as you use a mocking framework that is flexible enough to meet your testing needs.

Moq

Moq (I prefer the "mock" pronunciation just because it’s only one syllable instead of two) is a newer mocking framework for .NET that leverages many of the new platform and language features that arrived in .NET 3.5.  This gives it an advantage over older mocking frameworks that were stuck using the features that were available in previous versions of .NET. 

Getting started with Moq is easy.  Just grab the DLL, add a reference to it, and start coding.  Note that we will be using Moq 3.0 Beta, and that there are some major changes from 2.6 to 3.0, so the code below may need to be modified somewhat if you are using an older version.

Our First Test

Let’s revisit our LogMonitor from the previous post.  Recall that this class takes in a log message, then dispatches an E-mail if the message contains the string "error".  Originally, the class was tied directly to SmtpClient, but we applied the adapter pattern and dependency injection to simplify the tests.  Here’s the original LogMonitor code:

   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: }
  42:  
  43: /// <summary>
  44: /// Wrapper interface for <see cref="SmtpClient"/>.
  45: /// </summary>
  46: public interface ISmtpClient
  47: {
  48:     /// <summary>
  49:     /// Sends an E-mail.
  50:     /// </summary>
  51:     /// <param name="from"></param>
  52:     /// <param name="recipients"></param>
  53:     /// <param name="subject"></param>
  54:     /// <param name="body"></param>
  55:     void Send(string from, string recipients, string subject, string body);
  56: }
  57:  
  58: /// <summary>
  59: /// Adapts <see cref="SmtpClient"/> into the <see cref="ISmtpClient"/>
  60: /// interface.
  61: /// </summary>
  62: public class SmtpClientAdapter : ISmtpClient
  63: {
  64:     /// <summary>
  65:     /// Sends an E-mail.
  66:     /// </summary>
  67:     /// <param name="from"></param>
  68:     /// <param name="recipients"></param>
  69:     /// <param name="subject"></param>
  70:     /// <param name="body"></param>
  71:     public void Send(string from, string recipients, string subject, string body)
  72:     {
  73:         SmtpClient client = new SmtpClient();
  74:         client.Send(from, recipients, subject, body);
  75:     }
  76: }

And the LogMonitor tests:

   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: }

Notice that we had to create a test class to serve as the mock object for LogMonitor.  All is well.  But wait, the requirements are about to change!  Now we need to extend LogMonitor to handle warning messages, and warning and error messages need to go to two different accounts.  Well, we *could* modify our test class to track the E-mails that were sent, then verify that the correct E-mail was sent for each log message we pass in, but then what’s going to happen when they want to add support for "fatal" log messages?  Or super-critical-urgent messages?  Our simple test class is going to become complicated in a hurry. 

Enter Moq.  Moq let’s us get rid of the test class for ISmtpClient completely.  Instead, we’ll let Moq dynamically create a mock object for us.  All we have to do is setup the expectations, the actions we expect the mock object to perform in response to certain method calls.  In Moq 2.x, you did this using the Expects method, but in Moq 3.0, you use the new Setup method.  For our first test, let’s verify that error messages are being sent to the new address by using Moq:

   1: /// <summary>
   2: /// Verifies that the method correctly sends an E-mail 
   3: /// when it receives an error log.
   4: /// </summary>
   5: [Test]
   6: public void InspectLogMessage_SendsErrorEmail()
   7: {
   8:     var mock = new Mock<ISmtpClient>(MockBehavior.Strict);
   9:  
  10:     mock.Setup(c => c.Send("[email protected]", "[email protected]", "Error!", It.IsAny<string>())).AtMostOnce();
  11:  
  12:     LogMonitor monitor = new LogMonitor(mock.Object);
  13:  
  14:     monitor.InspectLogMessage("This is an error.");
  15:  
  16:     mock.Verify(c => c.Send("[email protected]", "[email protected]", "Error!", It.IsAny<string>()));
  17: }

There are a few important things to call out here.  First, we are creating a strict mock, which means that any calls to the mock which aren’t configured using the Setup method will result in exceptions.  Note how we setup our expectations by specifying the exact values we expect for most of the parameters, but we use It.IsAny for the last parameter.  That says "match any string value" for the last argument.

Second, the mock reference we create can’t be passed directly in as an ISmtpClient.  You might think that Moq could provide an automatic cast or something, but the .NET framework just won’t allow it in the current version.  So, to get to the actual mocked object, you access the Object property.  Simply pass mock.Object in to LogMonitor just as you would any class that implements ISmtpClient

Finally, notice that we have a call to Verify at the end.  This will throw an exception if the exact call specified wasn’t executed.  It is important to make sure that this matches the call you specified to Setup, otherwise your test will fail. 

Go ahead and run the test.  It should fail because we haven’t changed the address that error E-mails are being sent to.  Do that now by editing LogMonitor, replacing "[email protected]" with "[email protected]".  Re-run the test, and it should pass.

Next, let’s add a test for the warning messages.  It looks almost identical to the test for errors:

   1: /// <summary>
   2: /// Verifies that the method correctly sends an E-mail when
   3: /// it receives a warning log.
   4: /// </summary>
   5: [Test]
   6: public void InspectLogMessage_SendsWarnEmail()
   7: {
   8:     var mock = new Mock<ISmtpClient>(MockBehavior.Strict);
   9:  
  10:     mock.Setup(c => c.Send("warnings[email protected]", "[email protected]", "Warning!", It.IsAny<string>())).AtMostOnce();
  11:  
  12:     LogMonitor monitor = new LogMonitor(mock.Object);
  13:  
  14:     monitor.InspectLogMessage("This is a warning!");
  15:  
  16:     mock.Verify(c => c.Send("[email protected]", "[email protected]", "Warning!", It.IsAny<string>()));
  17: }

Again, run the test to be sure that it fails before you start making changes to the class-under-test.  Once you’re sure it fails, change the InspectLogMessage like so:

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

Run the test, and everything should pass!

More Mocking

We’ve only looked at a *very* trivial example so far, so you may be asking questions like "Can I mock a method that returns something?" and "Can I mock events and properties?"  The answer to both these questions is "yes!"  The Moq website has a very extensive Quick Start that illustrates the full power of Moq (note that it hasn’t been updated for Moq 3.0 yet, so translate Expect to Setup as you are reading the code).  Let’s look at a few of the really cool features.

Automatically mock properties

You can easily stub-out simple properties using the Stub extension method, like so:

   1: [Test]
   2: public void Stub_DoesGreatThings()
   3: {
   4:     var context = new Mock<HttpContextBase>();
   5:     //We want context to track the User property.
   6:     context.Stub(c => c.User);
   7:  
   8:     //When we assign the value here, it is automatically persisted for us, no
   9:     //need to wire it in manually.
  10:     context.Object.User = new GenericPrincipal(new GenericIdentity("Matt"), new[] {"Blogger"});
  11:  
  12:     Assert.AreEqual("Matt", context.Object.User.Identity.Name);
  13: }

Try that example both with and without the call to Stub to see the difference.  For more complicated properties, or to assign a default, use the overload that takes a second parameter:

   1: [Test]
   2: public void Stub_WorksWithComplexTypes()
   3: {
   4:     var context = new Mock<HttpContextBase>();
   5:     //This attaches a new handler to the Handler property.
   6:     context.Stub(c => c.Handler, new DefaultHttpHandler());
   7:  
   8:     Assert.IsNotNull(context.Object.Handler);
   9: }

You can also stub out all properties on the mock in a single call using StubAll.

Recursive Mocking

Need to mock an entire object graph?  Moq has you covered:

   1: [Test]
   2: public void RecursiveMock()
   3: {
   4:     var context = new Mock<HttpContextBase> {DefaultValue = DefaultValue.Mock};
   5:  
   6:     //These properties are now mocked!
   7:     Assert.IsNotNull(context.Object.Request);
   8:     Assert.IsNotNull(context.Object.Response);
   9:  
  10:     //And we can get back the mocked reference and setup expectations!
  11:     var response = Mock.Get(context.Object.Response);
  12:     response.Setup(r => r.Write("Hello, world!"));
  13:  
  14:     context.Object.Response.Write("Hello, world!");
  15:  
  16:     response.Verify(r => r.Write("Hello, world!"));
  17: }

Every return value that can be mocked (meaning it is an interface or an unsealed class with overridable members) will be mocked.  You can get the Mock wrapper around a mocked member via the Mock.Get static method.  This is *very* handy when you are mocking complicated types (you know, like HttpContextBase in your ASP.NET MVC applications).

The Dangers of Mocking

Moq makes it very easy to create mocks, but you should be careful.  Mocking is *not* a substitute for good design, and be careful not to write tests that depend on the internal behavior of the method you are testing.  Remember that your tests should verify that a method does what it says it will do; it’s not meant to verify how the method is doing it.  Here’s a great example of a bad test:

   1: [Test]
   2: public void BadTest()
   3: {
   4:     var mock = new Mock<IDatabase>();
   5:     mock.Setup(d => d.GetCustomer(5));
   6:     mock.Setup(d => d.SaveCustomer(It.IsAny<Customer>()));
   7:  
   8:     CustomerController controller = new CustomerController(mock.Object);
   9:  
  10:     //All this should do is update the record in the database.  For now, 
  11:     //let's assume it does this by retrieving the old record, updating it,
  12:     //then pushing everything back into the DB.
  13:     controller.ChangeCustomerAddress(5, "1111 New Street");
  14:  
  15:     //This isn't really part of the ChangeCustomerAddress contract, is it?
  16:     //Why do we care how it gets the customer...
  17:     mock.Verify(d => d.GetCustomer(5));
  18:     //But this one, we do care about; we do care that the Customer was pushed
  19:     //back to the database.  In fact, we might want to tighten down this verify...
  20:     mock.Verify(d => d.SaveCustomer(It.IsAny<Customer>()));
  21: }

Notice how we’re verifying that the method is making a call to our mocked database.  Well, what happens if we decide to implement some sort of caching scheme in our class-under-test?  The method is still doing exactly what it says its going to do, but it will no longer make a call to our mocked database.  If we added caching, we’d have to change our test even though the actual behavior of our method hasn’t changed (which is Bad). 

Wrapping It Up

Well, I hope that was a useful crash-course on using Moq.  For the next post in this series, I’m planning on screen-capturing a brief coding session of me doing test driven development.  The only snag is that I’ve got to find a project that I can show (obviously my current employer isn’t too keen on sharing code that they’re paying for).  Because of that, it may be a little while before you see part 6, but hopefully I’ll have some other topics to talk about Real Soon Now.