Evolution of a hand rolled fake

I usually hand roll my own fake objects for my tests. They have always looked a lot like what Stubs generate. I just think that it's so cheap to create them that I don't even need Stubs. In this series I'll assume an interface that looks like this:

   1: interface ITheInterface
  2: {
  3:     void DoSomething(int x);
  4:     int ComputeSomething(int a, int b);
  5: }

When I first started to hand roll my fakes it looked something like this:

   6: private class FakeTheInterface : ITheInterface
  7: {
  8:     public Action<int> DoSomethingHandler { get; set; }
  9:     public Func<int, int, int> ComputeSomethingHandler { get; set; } 
 10:  
 11:     public void DoSomething(int x)
 12:     {
 13:         if (DoSomethingHandler == null)
 14:         {
 15:             Assert.Fail("Unexpected call to DoSomething");
 16:         }
 17:  
 18:         DoSomethingHandler(x);
 19:     }
 20:  
 21:     public int ComputeSomething(int a, int b)
 22:     {
 23:         if (ComputeSomethingHandler == null)
 24:         {
 25:             Assert.Fail("Unexpected call to ComputeSomething");
 26:         }
 27:  
 28:         return ComputeSomethingHandler(a, b);
 29:     }
 30: }

Which gave you a test that looked something like this:

  31: [TestMethod]
 32: public void UsingFake1()
 33: {
 34:     var thing = new FakeTheInterface();
 35:     thing.ComputeSomethingHandler = (a, b) => 42;
 36:     Assert.AreEqual(42, thing.ComputeSomething(0, 0));
 37: }

After a while I realized that I could make the fake a little nicer by doing this:

  38: private class FakeTheInterface : ITheInterface
 39: {
 40:     public Action<int> DoSomethingHandler { get; set; }
 41:     public Func<int, int, int> ComputeSomethingHandler { get; set; }
 42:  
 43:     public void DoSomething(int x)
 44:     {
 45:         Assert.IsNotNull(DoSomethingHandler, 
 46:             "Unexpected call to DoSomething");
 47:         DoSomethingHandler(x);
 48:     }
 49:  
 50:     public int ComputeSomething(int a, int b)
 51:     {
 52:         Assert.IsNotNull(ComputeSomethingHandler, 
 53:             "Unexpected call to ComputeSomething");
 54:         return ComputeSomethingHandler(a, b);
 55:     }
 56: }

But once in a while I came across an interface with a method that had a method like FooHandler. "FooHandlerHandler" is just very confusing. Recently I tried a different approach that looks like this:

  57: private class FakeTheInterface : ITheInterface
 58: {
 59:     private Action<int> doSomething = 
 60:         x => Assert.Fail("Unexpected call to DoSomething({0}).", x);
 61:  
 62:     private Func<int, int, int> computeSomething =
 63:         (a, b) =>
 64:             {
 65:                 Assert.Fail(
 66:                     "Unexpected call to ComputeSomething({0}, {1}).",
 67:                     a, b);
 68:                 return 0;
 69:             };
 70:  
 71:     public FakeTheInterface(
 72:         Action<int> DoSomething = null, 
 73:         Func<int, int, int> ComputeSomething = null)
 74:     {
 75:         doSomething = DoSomething ?? doSomething;
 76:         computeSomething = ComputeSomething ?? computeSomething;
 77:     }
 78:  
 79:     public void DoSomething(int x)
 80:     {
 81:         doSomething(x);
 82:     }
 83:  
 84:     public int ComputeSomething(int a, int b)
 85:     {
 86:         return computeSomething(a, b);
 87:     }
 88: }

Note that I abuse the naming guidelines for arguments in order to make it consistent with the method name. A test using this fake looks like this:

  89: [TestMethod]
 90: public void UsingFake3()
 91: {
 92:     var thing = new FakeTheInterface(
 93:         ComputeSomething: (a, b) => 42);
 94:     Assert.AreEqual(42, thing.ComputeSomething(0, 0));
 95: }

So far I'm happy with this evolution. The only potential problem I see is if I need to replace the implementation half way through a test, but that can still be achieved by having a seperate variable in the test that I use and then change. So all in all it feels like this last evolution will be used (by me) for a while. Suggestions on improvements welcome!