Click here to Skip to main content
15,885,365 members
Articles / DevOps / Unit Testing

Exposing Fixture Object mocks

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
28 Sep 2014CPOL3 min read 6.2K  
Expose your mocks directly from the Fixture Object if possible. If there is no real need to complicate things by converting types and introducing extension methods, don’t do it.

A few weeks ago, I stumbled upon a coworker’s tests that use Fixture Object pattern. It is a nice way to simplify tests by moving setup code and repetitive helper methods to their own class. However, one thing did not seem quite right to me: tests that used mock objects from the fixture object needed to call an extension method AsMock() to run asserts on them. Since I was told that this approach is taken from one of Mark Seemann’s Pluralsight courses, that’s where I went for an answer and found Advanced Unit Testing course.

The example of Fixture Object usage in lessons includes the following code:

C#
var fixture = new BasketControllerFixture();
var sut = fixture.CreateSut();
var basket = fixture.Basket.WithSmallDiscount().Build();
var channelMock = fixture.channel.AsMock();

Notice that the fixture object exposes it’s dependencies as public fields. However, even when they are mocked, the original type of dependency is used. The mocking framework used in video lessons is Moq and its main class is Mock(T). What the AsMock() extension method does under the hood is simply convert an object back to type of Mock(T).

One of the reasons I don’t like it is that AsMock() is an extension method that affects all types. A few years ago, I switched my default mocking framework from Rhino Mocks to Moq. I like that Mock(T) in Moq encapsulates and hides all the setup and assert methods that you can run on a mock away from your code. In Rhino Mocks, however, all these methods are extension methods on type of object. That means you can call them on any object, but, of course, most of them would fail if it’s not a mock object. And then, there’s also a huge intellisense suggestion list every time you want to call a method or access a property of an object. In my opinion, that’s a great deal of noise when you write code.

Another problem is type conversion back and forth:

C#
//In the fixture:
public class TestFixture
{
    public IDependency dependency;

    public TestFixture()
    {
        // 1: we create and setup a mock
        var mock = new Mock<IDependency>();
        // 2: from mock type to interface type
        dependency = mock.Object;
        ...
    }
}
...
// 3: in test, we convert the dependency back to a Mock(T) type
var fixture = new TestFixture();
var dependencyMock = fixture.dependency.AsMock();
dependencyMock.Verify(x => x.Test(), Times.Exactly(1));

That only makes the code harder to understand without any apparent advantages. From what I’ve seen, most often we use the object to assert that some method was called on the mock. And if we would need it as a dependency for another object, the code should go into the fixture anyway. This means that from outside of the fixture object class, we always need a mock. We would always call AsMock(). I do not see any value in exposing an IDependency object, if we never use it.

What I ended up doing in our project’s tests is refactor these fixture objects to expose a Mock(T) object directly and then delete AsMock() extension method from our codebase. This had no impact on test results, but the code ended up easier to understand:

C#
public class TestFixture
{
    public Mock<IDependency> dependencyMock;

    public TestFixture()
    {
        dependencyMock = new Mock<IDependency>();
        ...
    }
}
...
var fixture = new TestFixture();
fixture.dependencyMock.Verify(x => x.Test(), Times.Exactly(1));

Conclusion

Expose your mocks directly from the fixture object if possible. If there is no real need to complicate things by converting types and introducing extension methods, don’t do it.

That said, this might only apply when using a framework like Moq that has a dedicated type for all mocks. Maybe Mark Seemann used this approach to be consistent with all other mocking frameworks. In the video, he even named AsMock() extension method’s class MockEnvy, indicating that it is a kind of code smell. However, some people who watch these videos and try this approach will actually do it in a copy-paste manner, without really trying to simplify things.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Lithuania Lithuania
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --