Mocking The Unmockable

14Oct08

Recently I was building an HttpModule project, and quickly ran into a serious problem: I couldn’t test my code.  The reason?  I was using objects that were unmockable.

The scenario involved passing an HttpContext object into my module so that I could manipulate certain properties.  What’s wrong with that?  Well, for starters HttpContext is sealed, along with every property attached to it that I needed.  My standard approach is to use Rhino Mocks, which has served me well in the past.  But here I hit a wall – or rather Rhino Mocks did.

Take a look at the snippet below, which demonstrates the problem.  I’m creating a very simple dynamic mock of HttpContext, and attempting to pass it to my interface (which accepts HttpContext – I’m omitting the interface here for brevity)…

[Test]
public void Should_Be_Mockable_But_Is_Not()
{
    HttpContext context = _repository.DynamicMock<HttpContext>(typeof (HttpContext), null);
    IMyModule module = new MyModule();
    module.ProcessRequest(context);
}

When I run this test, I get this unpleasant error:

TestCase 'MyTests.Should_Be_Mockable_But_Is_Not'
failed: System.NotSupportedException : Can't create mocks of sealed classes

Sealed?!  What is this nonsense?!  And then, the furrowing of my brow as my brain struggled to comprehend… “oh, right… ahem… sealed”.  Apparently one cannot just go right out and mock a sealed class these days.

But I didn’t want to change my object to make it more mockable; I needed that HttpContext object, or at the very least, another property on it which no doubt would also be sealed.  Rhino Mocks couldn’t deal with it; what could I do?

Enter Typemock Isolator

I had to do a lot of searching, but somehow I found my way past duck-typing (which I thought was interesting, but just too much work in this scenario) over to Typemock.  I didn’t really know it very well, other than it was yet-another-mock-framework.  But it did one thing Rhino Mocks didn’t do – it mocked sealed objects.  And that was enough to get my attention.

So how did I mock the unmockable with Typemock Isolator?  I used this forum thread as my guide, the basic gist of which is to initialize some MockObjects to the type that I want to mock, and use those as the initialization values for my real objects that I’ll pass in my tests.

The sample below shows a full setup and one test.

protected MockObject _mockHttpContext;
protected MockObject _mockRequest;
protected HttpContext _context;
protected HttpRequest _request;
 
[TestFixtureSetUp]
public void TestFixtureSetUp()
{
    MockManager.Init();
 
    // Create a mocked HttpContext object.
    _mockHttpContext = MockManager.MockObject(typeof (HttpContext), Constructor.Mocked);
    _context = _mockHttpContext.Object as HttpContext;
 
    // Create a mocked HttpRequest object.
    _mockRequest = MockManager.MockObject(typeof (HttpRequest), Constructor.Mocked);
    _request = _mockRequest.Object as HttpRequest;
 
    // Configure context to return a Request object.
    _mockHttpContext.ExpectGet("Request", _request, 1);
}
 
[Test]
public void Should_Definitely_Be_Mockable_Now()
{
    IMyModule module = new MyModule();
    module.ProcessRequest(_context);
}

Sounds great!  What’s the catch?

So Typemock can solve my unmockable problem for me.  Excellent.  But what’s the catch?  Rhino Mocks is free, Typemock Isolator is not.  This can make all the difference depending on budget, need, and other constraints.  For me in this situation, it’s well worth the price, though.

This may be one of those situations where I’m not supposed to be trying to test code that passes around sealed objects.  Or, maybe I could rewrite my code so that I’m getting what I need, but everything is testable without having to go outside Rhino.  I’m willing to concede that much.  But in this case, I’m keeping my module intact, but I’ve also got the testability I need.  So I’m happy.

Technorati Tags: ,,
Advertisements


2 Responses to “Mocking The Unmockable”

  1. 1 R. Eric Geiger

    Gil,Thanks for the update; that is fantastic information, and I have to admit I didn’t take the time to go past MockObject and review Isolator further.The syntax you show is clean and simple, two of my favorite attributes. I can’t wait to try it out in my project, and I plan to do a follow-up or update to this post as well.

  2. 2 Gil Zilberfeld

    Hi,I just blogged on using Isolator (with the new API) to easily fake HttpContext. It’s even easier than with MockObject, and more readable.Gil Zilberfeld, TypemockBlog: Blog.Typemock.com



%d bloggers like this: