Monday, July 27, 2009

Why another mock framework?

FluentSpec was announced as a BDD framework trying to avoid mock controversy, in particular the one caused by test doubles. But a Mock is both, a test double and a development practice, there’s no way to avoid the term. And BDD is mainly a communication practice that goes far beyond using the GWT syntax to write unit tests. FluentSpec is better described as a mock framework with a BDD flavor.

There are multiple mock frameworks in C#: RhinoMocks, Moq, NMocks and TypeMock. I started with NMocks and switched to Rhino. At that moment the main reason for the switch was that NMock was using literals to setup calls. RhinoMocks kept me happy until my style of development required more isolation of the SUT. Isolation is the specialty of TypeMock, but I think it goes too far allowing the usage of Band-Aids in places where we should stitch.




[TestClass]
public class
when_defining_a_complex_method {

    [
TestMethod]
    public void
should_split_in_simpler_methods() {

        var
Mocks = new MockRepository();
        var
Subject = Mocks.PartialMock<Subject>();

       
Mocks.ReplayAll();

       
Subject.ComplexMethod();

       
Subject.AssertWasCalled(x => x.DoASimpleMethod());
       
Subject.AssertWasCalled(x => x.DoAnotherSimpleMethod());
    }
}

public class
Subject {

    public void
ComplexMethod() {

       
DoASimpleMethod();
       
DoAnotherSimpleMethod();
    }

    public virtual void
DoASimpleMethod() {
        throw new
System.NotImplementedException();
    }

    public virtual void
DoAnotherSimpleMethod() {
        throw new
System.NotImplementedException();
    }
}




My conflict with RhinoMock can be expressed with this test




[TestClass]
public class
when_defining_a_complex_method : BehaviorOf<Subject> {
    
    [
TestMethod]
    public void
should_split_in_simpler_methods() {
        
       
When.ComplexMethod();
       
Should.DoASimpleMethod();
       
Should.DoAnotherSimpleMethod();
    }
}




This test throws System.NotImplementedException() which might be really easy to fix by removing that line. However, in terms of isolation it implies that when I wanted to test only the ComplexMethod I also ran the other dependent methods. Running the depended methods might lead to a failure at another level of abstraction. It could be possible to abstract that call in a dependency. But then I would not need a PartialMock and I would not be ripping the full benefits of the Composed Method pattern.

The test could be written in FluentSpec and would pass despite the throw clause.

That is in essence the reason why I needed another mock framework and why I could not wrap it around an existing one. The other reasons are also shown in this example.

.: Simplifies test setup




// with RhinoMocks
var Mocks = new MockRepository();
var Subject = Mocks.PartialMock<Subject>();
Mocks.ReplayAll();

// with fluentspec
BehaviorOf<Subject>




.: Doesn’t have test doubles like Stub, Mock or PartialMock. It has only a TestObject

.: Avoids repetitions of SUT references like




// with RhinoMocks
Subject.ComplexMethod();
Subject.AssertWasCalled(x => x.DoASimpleMethod());
Subject.AssertWasCalled(x => x.DoAnotherSimpleMethod());

// with fluentspec
When.ComplexMethod();
Should.DoASimpleMethod();
Should.DoAnotherSimpleMethod();




.: And doesn’t need lambdas or delegates to setup and verify calls

No comments:

Post a Comment