Test Specific Subclasses vs Partial Mocks

code, tdd 0 comments suggest edit

Sometimes when writing unit tests, you run into the case where you want to override the behavior of a specific method.

Here’s a totally contrived example I just pulled from my head to demonstrate this idea. Any similarity to specific real world scenarios is coincidental ;). Suppose we have this class we want to test.

public class MyController
{
  public void MyAction()
  {
      RenderView("it matches?");
  }

  public virtual void RenderView(string s)
  {
      throw new NotImplementedException("To ensure this method is overridden.");
  }
}

What we have here is a class with a public method MyAction that calls another virtual method, RenderView. We want to test the MyAction method and make sure it calls RenderView properly. But we don’t want the implementation of RenderView to execute because it will throw an exception. Perhaps we plan to implement that later.

Using A Partial Mock

There are two easy ways to test it. One is to create a partial mock using a Mocking framework such as Rhino Mocks.

[TestMethod]
public void DoMethodCallsRenderViewProperly()
{
  MockRepository mocks = new MockRepository();
  MyController fooMock = mocks.PartialMock<MyController>();
  Expect.Call(delegate { fooMock.RenderView("it matches?"); });
  mocks.ReplayAll();

  fooMock.MyAction();
  mocks.VerifyAll();
}

If you’re not familiar with mock framework, what we’ve done here is dynamically create a proxy for our MyController class and we’ve overridden the behavior of the RenderView method by setting an expectation. Basically, the expectation is that the method is called with the string “it matches?”. At the end, we verify that all of our expectations were met.

This is a pretty neat way of testing abstract and non-sealed classes. If a method does something that would break the test, and you don’t want to deal with that, or you don’t care if that method even runs, you can use this technique.

However, there are two problems you might run into this approach. First, VerifyAll doesn’t allow you to specify a message. That is a minor concern, but it’d be nice to supply an assert message there.

Secondly, and more importantly, what if RenderView is protected and not public? You won’t be able to use a partial mock (at least not using Rhino Mocks).

Using a Test-Specific Subclass

One approach is to use a test-specific subclass. I’ve used this test pattern many times before, but didn’t know there was a name for it till my colleague, Chris Tavares of the P&P group (no blog as far as I can tell), told me about the book xUnit Test Patterns: Refactoring Test Code.

In the book, the author categorizes various useful test techniques into groups of test patterns. The Test-Specific Subclass pattern addresses the situation described in this post. So looking at the above code, but assuming that RenderView is protected, we can still test it by doing the following.

[TestMethod]
public void DoMethodCallsRenderViewProperly()
{
  FooTestDouble fooDouble = new FooTestDouble();
  fooDouble.MyAction();
  Assert.AreEqual("it matches?", fooDouble.ReceivedArgument, "Did render the right view.");
}

private class FooTestDouble : MyController
{
  public string ReceivedArgument { get; private set; }

  protected override void RenderView(string s)
  {
      this.ReceivedArgument = s;
  }
}

All we did was write a class specific to this test called FooTestDouble. In that class we override the protected RenderView method and set a property with the passed in argument. Then in our test, we can simply check that the argument matches our expectation (and we get a human friendly assert message to boot).

Is this a valid test pattern?

Interestingly enough, I have shown this technique to some developers who told me it made them feel dirty (I’m not naming names). They didn’t feel this was a valid way to write a unit test. One complaint is that one shouldn’t have to inherit from a class in order to test that class.

So far, none of these complaints have provided empirical reasons behind this feeling that it is wrong. One complaint I’ve heard is that we are not testing the class, we are testing a derived class.

Sure, we’re technically testing a subclass and not the class itself, but we are in control of the subclass. We know that the behavior of the subclass is exactly the same except for what we chose to override.

Not only that, the same argument could be applied to using a partial mock. After all, what is the mocking example (which many feel is more appropriate) doing but implicitly generating a class that inherits from the class being tested whereas this pattern explicitly inherits from the class.

My own feeling on this is - I want to choose the technique that involves less code and is more understandable for any given situation. In some cases, using a mock framework does this. For example, in the first case when RenderView is public, I like having my test fully self-contained. But in the second case, RenderView is protected, I think the test-specific subclass is perfectly valid. The test-specific subclass is also great for those who are not familiar with a mock framework.

While some guidelines around TDD and unit testing are designed to produce better tests (for example, the Red Green approach and trying not to touch external resources such as the database) and better design, I don’t like to subscribe to arbitrary rules that only make writing tests harder and don’t seem to provide any measurable benefit based on some vague feelingof dirtiness.

Tags: TDD , Unit Testing , Test Specific Subclass

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

18 responses

  1. Avatar for Ayende Rahien
    Ayende Rahien December 6th, 2007

    Can you explain what you mean by VerifyAll not having a message?

  2. Avatar for Haacked
    Haacked December 6th, 2007

    I mean I can't specify my own assert message. If the expectations are not met, VerifyAll throws an exception, which provides a lot of information, but for the sake of my unit test, I may want to specify a message like I would with Assert.

  3. Avatar for jbogard
    jbogard December 6th, 2007

    Feathers calls this technique "subclass and override" in his Legacy Code book, but it's the same thing. This is a very common technique when dealing with legacy code, and I have to do this a lot with non-virtual members too (http://grabbagoft.blogspot.....
    I don't feel dirty if I'm already swimming in mud.

  4. Avatar for Oran
    Oran December 6th, 2007

    You can specify your desired "assert" message on each Expect.Call. So using your example, it would look like this:
    Expect.Call(delegate { fooMock.RenderView("it matches?"); }).Message("Did render the right view.");

  5. Avatar for Oran
    Oran December 6th, 2007

    The way you're using the Test-Specific Subclass is as a Stub (state-based). To me, a partial mock (interaction-based) also qualifies as Test-Specific Subclass. In the Ben Pryor post that you linked to from here, he says "A stub is a trivial implementation of an interface that exists for the purpose of collecting state during a unit test." Since as you mentioned you prefer state-based testing over Interaction-based testing, a Stub (state-based) would feel more natural to use than a Mock (interaction-based).
    In the case of your controller, the essence of your test is the controller's interaction with its view, so I would argue that interaction-based testing is more appropriate. You can simulate interaction-based testing with a Stub, but it has the disadvantage of jumping through the extra hoops of explicit state accumulation and retrieval/verification rather than just directly expressing the expected behavior.

  6. Avatar for Aaron Jensen
    Aaron Jensen December 6th, 2007

    Isn't this really just telling us that Controller should not have a RenderView method?

  7. Avatar for Haacked
    Haacked December 6th, 2007

    @Oran re: Message, Oh! I did not know that. Thanks!
    @Aaron what should it have instead?

  8. Avatar for Sean Chambers
    Sean Chambers December 6th, 2007

    I use this way of performing unit tests pretty often. Namely while testing repositories that need a specific nhibernate session injected. During my test fixture setup I create a sqlce session and then derive from my repositories so I can set the session with my sqlce session instead of the configuration file session.
    Another pattern that is better equiped for testing static/singleton objects Hammett has described here: http://hammett.castleprojec...
    All this is doing is just wrapping the behavior inside of another class with an interface. Then you can mock out the interface at runtime. The benefit here is that you have taken something that could not be tested and wrapper it with an interface you control and thus can be mocked!
    This can be used in any scenario including the one you describe above. The side effect is that it does create more code but in certain scenarios it is justified. I weigh each option closely and then make a decision on what would best serve my context. It is not often that I use the code hammett described there but sometimes it does come in useful.

  9. Avatar for Thomas Wagner
    Thomas Wagner December 6th, 2007

    I meant to comment about this before and never got around to it. You are one of the most diligent TDD devs that I know in the .NET world. A place where a lot of people don't even know where to start with TDD. Which TDD framework should I use.... how do I deal with data or databases. Are there different ways to address some core problems. Should I write a test first? etc etc etc.
    Can I recommend that time permitting you write down your own experience in a how-to series. I think it would be tremendously useful to a lot of people and really draws on one of your strengths.

  10. Avatar for Ted
    Ted December 6th, 2007

    Re: RenderView()
    I have to agree with Aaron. I am pretty new to the MVC concept but after doing a lot of studying, I am getting a waft of something that seems wrong from both Microsoft's MVC and the much lauded MonoRail.
    Microsoft's MVC(going off ScottGu's blog posts of it and the few other that are out there) seems to fall apart after the first level of Controller-View. What I mean is that after the URL is routed to the appropriate controller and action, the only thing you seem to be able to do is call a single View, with RenderView(). What about View re-use? Nesting Views? Microsoft's MVC seems, kind of like the CodeIgniter project for PHP, that a controller action has to know everything about what a View requires from the Model so that it can be displayed properly. If you want to re-use a View inside another Controller, it seems that you have to duplicate the means of getting the data into all the Views that you are displaying from that new Action.
    MonoRail has something called a ViewComponent to alleviate this but even from their own documentation, ViewComponent smells like a duplication of their Controller class.
    It all boils down to appearing to me that both of these frameworks require the Controller to pass the data from the Model to the View, rather than the View just grabbing it straight from the Model. There is nothing in the MVC pattern(that I am aware of) that prohibits the View from doing this either.
    Maybe I am just misunderstanding something crucial here though and would love to be corrected.

  11. Avatar for Haacked
    Haacked December 6th, 2007

    @Thomas Thanks for the suggestion. I've written a lot on the topic. I'll try to categorize what I've written and shore up areas that I haven't covered.
    @Ted
    > What about View re-use? Nesting Views?
    You can encapsulate views in user controls. Works great. You can call RenderView and specify a user control instead of a full page.
    Master pages still work, which is one form of nesting views.
    However, the thing you're probably referring to is how do we handle sub-controllers. That's not addressed in the upcoming CTP, but we are investigating multiple solutions.

  12. Avatar for DotNetKicks.com
    DotNetKicks.com December 7th, 2007

    You've been kicked (a good thing) - Trackback from DotNetKicks.com

  13. Avatar for mcgurk
    mcgurk December 7th, 2007

    The project I'm currently working on at my company uses custom app blocks to implement the provider model. We've got about seven different providers from logging to state machine. I've created mock implementations for many of them. Its a very convenient way to test objects that rely on the blocks. Set the MockDatabase.ThrowException, call your method, and assert on MockLog.LastErrorMessage. Yes, its extra code, but its incredibly simple code.

  14. Avatar for Aaron Jensen
    Aaron Jensen December 8th, 2007

    > @Aaron what should it have instead?
    A service with a RenderView method on it. Right now RenderView invokes the ViewFactory to Create the view and then calls RenderView on that view. It's nothing more than a helper method, but perhaps its a method that should be on an IViewRenderer? MS is making the same mistake MR made in putting way too much functionality on the controller.
    That said, with no changes to the framework, couldn't you just mock the IViewFactory to return a mock view and not have to do any of the awkward self-mocking/subclassing nonsense? Of course without reflector you wouldn't know you could do this... which just goes to show the flaw in the design.

  15. Avatar for Haacked
    Haacked December 8th, 2007

    @Aaron Ah! I see what you're saying. So it seems to me that you're suggesting we put another service in between Controller and IViewFactory. Is that right?
    Yes, I could have mocked IViewFactory, but after the IView is returned from the factory, the RenderView method also creates a ViewContext which is passed to the view when rendering which requires other dependencies I need to mock.
    It ends up being seriously less code than just overriding RenderView. Perhaps that's a code smell. Perhaps it's saying I should just override RenderView and go home. ;)
    Once the bits are out, I'd love to hear about your TDD experience and see how we can improve it.

  16. Avatar for you've been HAACKED
    you've been HAACKED December 9th, 2007

    Writing Unit Tests For Controller Actions

  17. Avatar for Alex McMahon
    Alex McMahon December 12th, 2007

    Very interesting, I recently wrote a blog post about how to test private methods on abstract classes using a combination of Partial Mocks, and the dubious MS Private accessors.
    http://icoder.wordpress.com...
    Where possible I avoid doing "test specific subclass" as I just find it really unreadable, and I find it hard to concentrate on which methods I am testing and which ones I'm overriding etc. Partial mocks (in general) lead to better readability IMO.

  18. Avatar for Chris Moorhouse
    Chris Moorhouse December 18th, 2007

    I guess really it depends on how "dirty" one feels about the alternatives to Test Specific Subclasses in the protected method case. You could always leave it untested !;)
    Being a novice and all, here's what I feel about this testable class creation right off the bat:
    Partial mocks = automated = good
    Test Specific Subclasses = manual = bad
    Yes, it's an oversimplification, but put it this way: why do you prefer "having my test fully self-contained" if you're not having the same "dirty" feeling that these other devs are expressing? Maybe you're just less sensitive to the dirt?