次の方法で共有


Mocking framework comparison

As you may know I think mocks should be used quite carefully. But as I've pointed out before I think you should use the best tool available and that means to use a mocking framework sometimes. One thing I've never really liked with the typical mocking framework is how it requires you to learn a new API to setup the test double. And if you don't know the API I think a typical mock setup can be very confusing if you see the code for the first time. However if you choose Stubs as your framework you get the benefit I'm looking for (primarily not having to hand roll my test doubles). You avoid a powerful framework that can mock things you shouldn't really mock (making your code easier to test by design rather than by use of framework). And also you do not require the user to learn a new API; Stubs uses standard language features (delegates and closures) to setup the stub.

There is actually a great project where you can compare different mocking frameworks (including Stubs) called mocking-frameworks-compare where you can study a number of different tests written with different frameworks. Here is one example from that project using Moq:

    1:  public void TouchHotIron_Yell()
   2:  {
   3:      var hand = new Mock<IHand>();
   4:      var mouth = new Mock<IMouth>();
   5:      hand.Setup(x => x.TouchIron(Match<Iron>.Create(x => x.IsHot))).Throws(new BurnException());
   6:   
   7:      var brain = new Brain(hand.Object, mouth.Object);
   8:      brain.TouchIron(new Iron { IsHot = true });
   9:   
  10:      mouth.Verify(x => x.Yell()); 
  11:  }

If you're not used to Moq I think there are a number of things that stand out as weird. First of all there is no assert in the test. Second the setup is not obvious. And it is not obvious that we are verifying Yell is being called or if Yell is going to be called by the verify method. Now, let's look at the same test using Stubs:

    1:  public void TouchHotIron_Yell()
   2:  {
   3:      var hand = new SIHand();
   4:      var mouth = new SIMouth();
   5:   
   6:      hand.TouchIron = (iron) =>
   7:      {
   8:          if (iron.IsHot)
   9:              throw new BurnException();
  10:      };
  11:      bool yelled = false;
  12:      mouth.Yell = () => yelled = true;
  13:   
  14:      var brain = new Brain(hand, mouth);
  15:      brain.TouchIron(new Iron { IsHot = true });
  16:   
  17:      Assert.IsTrue(yelled);
  18:  }

You might notice that the test is a little longer and feels more verbose. But that is not necessarily a bad thing. On the contrary I think that is a good thing. Also the only framework specifics you need to know is to use the stub-class and know it has a property to define behavior. Apart from that there is also a performance benefit from using Stubs which you can read more about here (note that the support for partial mocks that is mentioned as not yet supported is now supported). All this things considered I think Stubs is the best mocking framework choice you can do today.

Preemptive comment answer: But Stubs is not a mocking framework! Well I think it is because I can create mock objects, fakes and stubs (i.e. any kind of test double) with it. So the same thing as Moq or RhinoMocks for example. Same, same, but different...