Making the untestable testable with Anonymous Methods and Dependency Injection

Making the untestable testable with Anonymous Methods and Dependency Injection

It can be frustrating to want to write unit tests, only to hit some code which is rather untestable. Take for example, the following code:

public class MailSender
{
   public void SendActivationMail(User user, string activationCode)
   {
            string body = GetCopyOfActivationBody(); //implementation doesn't matter
            body = body.Replace("#NAME#", user.Name).Replace("#CODE#", activationKey).Replace("#EMAIL#", user.Email);
            var message = new MailMessage("support@piccolo.cool", user.Email, "Account Activation", content) {IsBodyHtml = true};
            new SmtpClient().Send(message);
   }
}

Obviously, I can’t test this method as-is without making sure that a mail server is setup. And even if it was, how would I verify that the properties of my MailMessage object were properly set?

In the past, I probably would have solved this by using a virtual method and mocking it:

public void SendActivationMail(User user, string activationCode)
{
        string body = GetCopyOfActivationBody(); //implementation doesn't matter
        body = body.Replace("#NAME#", user.Name).Replace("#CODE#", activationKey).Replace("#EMAIL#", user.Email);
        var message = new MailMessage("support@piccolo.cool", user.Email, "Account Activation", content) {IsBodyHtml = true};
        SendMessage(message);
}
public virtual void SendMessage(MailMessage message)
{
   new SmtpClient().Send(message);
}

Now we can create a mock of our MailSender class and mock our SendMessage method. I still think this is an acceptable solution, but I now prefer to inject an anonymous method as a dependency. The benefit is that my unit tests are more straightforward, and I’m not having to expose a method like SendMessage.

Before you move on, you should be familiar with anonymous methods, I’ve blogged about them in the past and/or you can check out this dimecast.

First we’ll change our MailSender class to accept a simple anonymous method into its constructor:

public class MailSender
{
   private readonly Action<MailMessage> _sendMessage;
   public MailSender(Action<MailMessage> sendMessage)
   {
      _sendMessage = sendMessage;
   }
}

Next we’ll change our SendActivationMail to use the sendMessage action:

public void SendActivationMail(User user, string activationCode)
{
   string body = GetCopyOfActivationBody(); //implementation doesn't matter
   body = body.Replace("#NAME#", user.Name).Replace("#CODE#", activationKey).Replace("#EMAIL#", user.Email);
   var message = new MailMessage("support@piccolo.cool", user.Email, "Account Activation", content) {IsBodyHtml = true};
   _sendMessage(message);
}

Before we write our test, let’s configure this dependency for our normal, production use. Here I’m using Ninject (some version of the 2.0 branch, so the syntax might be slightly different for you):

Bind<Action<MailMessage>>().ToConstant(message => new SmtpClient().Send(message));

That’s all there is to it. Now, whenever we get an instance of our MailSender class through Ninject, it’ll automatically inject the default behaviour and happily send emails away (for those curious where/how to configure the host/port/username/password, I prefer to do that in the web.config/app.config via the <system.net> section.) As for our tests, they look something like:

[Fact]
public void SendsActivationEmailToUser()
{
    var user = new User {Email = "nail@namekian.cool"};
    var action = new Action<MailMessage>(m => Assert.Equal(user.Email, m.To.ToString()));
    new MailSender(action).SendActivationMail(user, null);
}

There you have it. By injecting our own test-specific anonymous method into our MailSender class we’ve turned otherwise untestable code into code which is easy to test.

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

20 Responses to Making the untestable testable with Anonymous Methods and Dependency Injection

  1. Gordon McAllister says:

    This is great for mocking out functionally only found all those static classes that Microsoft made so unmockable! Like DateTime as mentioned above!

  2. Haacked says:

    I like this approach.

    If you think about it, for a moment, it kind of seems silly to have interfaces with a single method these days now that the Framework has a nice way of supplying lambdas.

    After all, there’s not much difference between an Action and an interface with a single method.

    Except that an action provides for even less coupling since your no longer coupled to an interface definition, but a method signature, which anyone can create anonymously.

  3. karl says:

    Sandor:
    If you are talking about server/port/username/password, I mentioned in my post that I would put those in the config file under the system.net section. These are automatically picked up by the SmtpClient class and used by default.

  4. Sandor Davidhazi says:

    Where would you modify the state of the SMTP client based on certain parameters if you would need to? Wouldn’t that place code that belongs to the MailSender class outside of it?

  5. Martin Evans says:

    In the context that its being used, it’s a really smart use (and example of) of anonymous methods. Its lean, simple and uses as little code as possible. I’m all for it.

    Thanks Karl.

  6. Tigraine says:

    I agree with Tom and Garry, I’d go with a special class that takes care of sending Emails.
    I believe that an Action is much less readable in the long term than a
    ISmtpSender with an accompanying SmtpSender class.

    The test code doesn’t change all that much, since I could use RhinoMocks directly on the interface to create an expectation.

  7. In case you need to inject only one method, like in this case, using lambda expression as a constructor parameter is simpler and more obvious than defining and using special interface. Interface makes sense if there are many methods which we need to mock.

  8. Dirk says:

    Completely agree with James:
    more options = good

    Especially if somebody writes a great example of how it fits in :-)

  9. James says:

    Interesting.

    I imagine this works well where you have one distinct “action”, the implementation of which is the thing you want to mock out.

    Definitely something I’ll keep in mind.

    Personally my knee-jerk approach would have been to create an ISmtpClient interface :)

  10. Using Func, Action instead of Mock object makes the unit test weired, difficult to find its intend, SystemTime.Now() is okay it does not distract the actual purpose of the test, but id does IMHO.

  11. Thed says:

    @David. This pattern is quite common in functional programming, also. It’s also seen in the .Net world a lot with Linq extension methods.

    Also, I like the Ninject love.

  12. Peter Seale says:

    I considered this approach for my own stuff, but then thought “naah, that’s getting crazy.” I think it’s straightforward to use and easy to mock, I’m just nervous that others will think it’s going too far.

    Side note: abstracting DateTime.Now would be one place to use this technique, and tons of folk have blogged about their approaches to abstracting it away… e.g. http://codebetter.com/blogs/dru.sellers/archive/2009/01/11/kick-the-datetime-now-addiction.aspx

  13. This looks closer to how dependencies are sometimes swapped out at test time for dynamic languages like Ruby and Python (based on my limited exposure to them).

    I think I like it – like Peter said, you’re actually asking for even more detail than just an interface. Sure, there will be times when you need to inject an interface, but this seems very lightweight. I’ll have to try it out.

  14. karl says:

    Sean,
    You mean through the SpecifiedPickupDirectory SmtpDeliveryMethod?

    Well first, I didn’t know about it until your comment :)

    Aside from that, I guess you could, but that seems like a lot more work and doesn’t seem like a unit test anymore. Which I agree doesn’t matter if it gets the job done, but larger tests tend to be more brittle.

  15. Peter says:

    I think I agree with Karl. When using an interface you’re saying: I have this MailSender class which depends on the ISmtpSender interface, but which method I’m using on this interface is not clear. When injecting an Action<> object you’re a bit more specific: you are telling MailSender depends on/uses this type of action/method.

  16. Sean Gough says:

    For testing, couldn’t you drop the mail message to a folder and then validate it? No mail server is needed and a little post-test cleanup to get rid of the dropped files could be added too.

  17. karl says:

    Funny, I thought this was a simpler and a more straightforward approach. Either works. I could see the facade being a much better choice if I wanted to use more methods of the SmtpClient class.

    I don’t see how the client is coupled to the SmtpSender. The dependency can be changed, and is being injected via auto-wiring.

  18. Tom de Koning says:

    Also and more important; haven’t now you created a coupling between the SmtpSender and the client?

  19. That’s exactly what I was thinking Tom, this way seems more complicated that implementing a simple facade over SmtpClient

  20. Tom de Koning says:

    Hey Karl, it sure looks funky and all that… but why not extract interface on the SmtpSender class and inject that using the DI container?

    Tom