How To Test Your Production Code: Using Fake Objects

In the last post we talked about Mock Objects and what are the difference between them and Spies. We have almost completed our journey through the all the different types of Test Doubles, in this post we are going to introduce the last one: the Fake Object. 

There are sometimes where the need of isolation comes from the fact that your tests are running too slow because you are accessing services that need to read or write to the disk or make a network call. In this cases, the best way to improve the test is to use a Test Double that only mimics the same functionality as the service you are currently using. Of course, you need a way to swap the objects during the test, but the techniques to be sure that you can inject your Test Doubles are going to be discussed in a future post.

Let’s make an example

Let’s pretend that you are developing a method that prepares different kind of SMS messages and then sends them using a service that returns an id for the message so you can query it back and check the processing status of the message. The service also stores all sent messages in a queue for later use and the queue has to be manually emptied.

class SmsManager
{
  public IMessageService SMSService { get; set; }
  public void SendSMS()
  {
    string message = PrepareSMS();
    Guid key = SMSService.Send(message);

    while (!SMSService.Sent(key))
    {
      Thread.Sleep(100);
    }
    SMSService.Delete(key);
  }

  private string PrepareSMS()
  {
    return String.Empty;
  }
}

Maybe we can configure the service to avoid sending the SMS message while we are in test, but we still have to wait for the whole round trip to happen, causing a sensible delay in getting the results from the test, and if we have to run lot’s of tests  those delays will start to add up. After a while, you end up with tests that take you minutes to run and you stop running them often.

Uncle Bob always talks about how he and his team developed FitNesse without needing a database. But how do they tested the functionalities that dealt with persistent data? well, they isolated the persistence layer and they faked it with an in-memory representation of it.

This is what Fake Objects are for: you swap slow external dependencies of your SUT with the Fake Object and you use them in your test as if they were real.

Can It Be THAT Simple?

Well, it depends. The problem is that Fake Object must have the same functionality as the real one, at least all the functionality the SUT uses, but implemented in a simpler way; for example, our fake SMS service could be implemented like this:


public interface IMessageService
{
  Guid Send(string message);
  bool Sent(Guid key);
  void Delete(Guid key);
}

public class FakeSmsService : IMessageService
{
  Dictionary<Guid, string> inmemorydb = new Dictionary<Guid, string>();
  public Guid Send(string message)
  {
    var guid = new Guid();
    inmemorydb.Add(guid, message);
    return guid;
  }
  public bool Sent(Guid key)
  {
    return inmemorydb.ContainsKey(key);
  }
  public void Delete(Guid key)
  {
    inmemorydb.Remove(key);
  }

}

Internally the fake service retains a dictionary of key-value pairs where it saves all the messages that the method Send receives. Even though it’s pretty simple, this implementation is powerful because we can trust that the SUT will believe that it’s using the SmsService that makes the HTTP calls and all that, but in fact, all the operations stay in the memory of the running process, so it’s waaay faster.

Could you give an example of a Fake Object recently used?

In one recent project we used Effort to isolate us from the database.

We were using Entity Framework code first to create the database and then access it, and we discovered this Effort that was an Entity Framework Provider: it implemented the same interfaces and functionality of EF but it did it in an in-memory database so we didn’t have to worry about cleaning the DB in the TearDown phase of our test, we simply destroyed it and created it again, and it was super-fast.

What to do next?

Find a simple functionality on the code you are maintaining that uses an external service and start implementing a fake object based on that functionality; then use it in a test suite to cover your method.  If the service is huge and with lots of functionality, don’t get overwhelmed, start small, just a simple implementation that helps you test the method you decided to cover.

 

After reading this series of posts you have no more excuses, now set up your environment and start testing the heck out of your code!

Most importantly help a friend by explaining him the difference between mocks and spies and if he doesn’t understand, send him the link to this post.

Advertisements

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