Lately I am using fake objects more than the other common kinds of doubles – stubs, spies and mocks. This is quite recent, I used to prefer stubs, spies or mocks. I find that fakes make my tests less fragile in the case of outside-in development when it comes to changes in the design. The problem is that there could be defects in the implementation of the fake objects. A tricky one may appear in the case of in-memory repositories:

public class InMemoryRepo : JobRepository {
   readonly List jobs = new List();
   public void Add(Job job)
   {
       jobs.Add(job);
   }
   public void Update(Job job)
   {
       // TODO
   }
   public List FindBy(string ownerId)
   {
        return jobs.Where(job => job.IsOwnedBy(ownerId)).ToList();
   }
}

This implementation is misleading. If we are test-driving a service expecting it to update a Job instance, we may forget to invoke the repository’s Update method and it would still work.

[TestClass]
public class ServiceTest {
   [Test]
   public void AssignsOwnerToJob()
   {
        var service = Factory.CreateJobServiceWithFakeRepository();
        var job = service.CreateJob(irrelevantTitle);

        service.Assign(job, irrelevantOwnerId);

        service.JobsOwnedBy(irrelevantOwnerId).Should().HaveCount(1);
   }
}

public class Service {
   private JobRepository repo {get; set;}

   public Service(JobRepository repo){ 
       this.repo = repo;
   }
   public Job CreateJob(string title)
   {
      var job = new Job();
      repo.Add(job);
      /*...*/
      return job;
   }
   public void Assign(Job job, string ownerId){
       /*...*/
       job.Assign(ownerId);    
       /* BUG: am forgetting the call to "repo.Update(job)" right here */
   }
   public List JobsOwnedBy(string ownerId){
       return repo.FindBy(ownerId);
   }
}

The problem is that the in-memory repository is using the same object references all the time. When an object is passed in as an argument, it’s actually a copy of the reference. However if the repository was accessing a database it would most likely return different instances (references). A better implementation of the repository would be this one:

public class InMemoryRepo : JobRepository {
   readonly List jobs = new List();
   public void Add(Job job)
   {
       /* clone: the object added to the repo 
                 is different to the given one */
       jobs.Add(job.Clone()); 
   }
   public void Update(Job job)
   {
       /* find the given job, 
          remove it from the collection and 
          add a clone of the given one */
   }
   public List FindBy(string ownerId)
   {
        return jobs.Where(job => job.IsOwnedBy(ownerId)).ToList();
   }
}

Conclusion: the behavior of the fake should be the same than the original when it comes to handling object references.