Getting Started With Mocking and Moq

posted on 08/08/08 at 12:45:40 am by Joel Ross

Lately, I've taken a keen interest in unit testing. I've started to rewrite some of my code to make it more test-friendly. One of the frustrating parts about doing that is that I found I was creating a lot of fake classes in my tests so that I would be able to test just a single part of my code, while holding other parts constant.

Maybe it's just because I always envisioned that testing would be pretty simple, but for some reason, having all of those extra (fake) classes around didn't sit well with me. So I decided to look into a mocking framework. Since I was using .NET 3.5 and I'd heard that Moq was built on that, I figured I'd give that a go. It's worked out quite well.

Imagine that I have a User class:

   1:  public class User
   2:  {
   3:     public FirstName { get; set; }
   4:     public LastName { get; set; }
   5:     public UserName { get; set; }
   6:     public Password { get; set; }
   7:     public Email { get; set; } 
   8:   
   9:     public User() { }
  10:   
  11:     public bool EmailPassword(IEmailSender emailSender)
  12:     {
  13:        string subject = "Your Password";
  14:        string body = String.Format("{0} {1}, your password is {2}", FirstName, LastName, Password);
  15:        return emailSender.Send(subject, body, Email);
  16:     }
  17:  }

One of the things you'll notice about code written to be tested is that it's very modular, so when a user requests their password, the User class doesn't know anything about how an email is sent - it just uses an interface, and it's up to the calling application to supply that. If you start to write all of your code this way, you'll quickly see the usefulness of using a dependency injection framework (such as Ninject) to handle resolving your dependencies for you. But that's not what I'm focused on here. As a matter of fact, I don't care about the actual implementation of IEmailSender that the application will use. All I care about is the interface:

   1:  public interface IEmailSender 
   2:  {
   3:     bool Send(string subject, string body, string email);   
   4:  }

If I want to test the EmailPassword method, I have a couple of options. I could create my own mock email sender and implement the Send method and have it return true. But what happens when I want to test what happens when it returns false? Or it throws an exception? Now I'm starting to write a lot of code in a fake implementation, strictly for the purpose of testing. While I think the benefits of doing that are there, I also think there's potentially a better way.

The second option is to use a mocking framework. When you work with a mocking framework, what you're doing is essentially implementing the interface on the fly, and telling it what it should return when methods are called. Let's look at an example of a test that just verifies that EmailPassword returns true when emailSender returns true:

   1:  [Test]
   2:  public void User_Can_Send_Password()
   3:  {
   4:     var emailMock = new Moq.Mock<IEmailSender>();
   5:     
   6:     emailMock
   7:        .Expect(sender => sender.Send(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
   8:        .Returns(true);
   9:     
  10:     User user = new User();
  11:     Assert.That(user.EmailPassword(emailMock.Object) == true);
  12:  }

Line four says that I want to create an implementation of the IEmailSender interface, so I can use that later in line 11, when I call EmailPassword. Notice the .Object - that's the dynamically created IEmailSender. Lines six, seven and eight are the meat of the mock. Line seven sets up how the mock should expect to be called. Any time Send is called, passing in any string for any of the parameters (the It.IsAny<string>() code), line eight specifies that it should return true.

Now if we wanted to verify that EmailPassword returns false when IEmailSender.Send returns false, it's just a matter of taking the above code and changing line eight to .Returns(false). Each test sets up the mock the way it wants, so the mock is isolated across tests. There's no need for any extra logic to determine what should be returned in scenarios beyond the scope of that test, like there would be if I created an actual MockEmailSender to cover all of the different cases.

There are different options with the expects (in line seven) to allow you to match that the correct parameters are passed as well. You can also add a .Verifiable() on the end of the mock setup code and then call emailMock.Verify() after you run your test code (so, after line 11) and verify that the method was actually called.

I'm still fairly new to Moq and mock objects in general, but so far, I'm impressed with what I've been able to do and how quickly I can do it.

Categories: Development, C#