Mark Needham

Thoughts on Software Development

TDD: Testing delegation

with 3 comments

I recently came across an interesting blog post by Rod Hilton on unit testing and it reminded me of a couple of conversations Phil, Raph and I were having about the best way to test classes which delegate some responsibility to another class.

An example that we ran into recently was where we wrote some code which required one controller to delegate to another.

public class ControllerOne extends Controller {
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
    }
}
public class ControllerTwo extends Controller {
	private final ControllerOne controllerOne;
 
	public ControllerTwo(ControllerOne controllerOne) {
		this.controllerOne = controllerOne;
	}
 
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		....
		return controllerOne.handleRequest(...);
    }
}

My initial thought when working out how to test this code was that we should check that the request is actually getting routed via ControllerOne:

@Test
public void theTest() {
	ControllerOne controller One = mock(ControllerOne.class);
 
	ControllerTwo controllerTwo = new ControllerTwo(controllerOne);
 
	controllerTwo.handleRequest(...)
 
	verify(controllerOne).handleRequest(...);
}

When we discussed this Raph and Phil both pointed out that we didn't care that specifically about the implementation of how the request was handled. What we care about is that the result we get after the request is handled is as expected.

We therefore changed our test to be more like this:

@Test
public void theTest() {
	ControllerOne controller One = mock(ControllerOne.class);
	ModelAndView myModelAndView = new ModelAndView();
	when(controllerOne.handleRequest(...).thenReturn(myModelAndView);
 
	ControllerTwo controllerTwo = new ControllerTwo(controllerOne);
 
	ModelAndView actualModelAndView = controllerTwo.handleRequest(...)
 
	assertThat(actualModelAndView, equalTo(myModelAndView));
}

I've been finding more and more recently that when it comes to writing tests which do some sort of delegation the 'stub + assert' approach seems to work out better than just verifying.

You lose the fine grained test that verifying mocks provides but we can still pretty much tell indirectly whether the dependency was called because if it wasn't then it's unlikely (but of course still possible) that we would have received the correct 'ModelAndView' in our assertion.

My current approach is that I'd probably only mock and verify an interaction if the dependency is a service which makes a network call or similarly expensive call where the interaction is as important as the result obtained.

For example we probably wouldn't want to make that call multiple times and with verification we're able to ensure that doesn't happen.

I find as I've used mocking frameworks more I feel like I'm drifting from a mockist style of testing to one getting closer to the classicist approach. I wonder if that's quite a normal progression.

Written by Mark Needham

November 27th, 2009 at 2:43 pm

Posted in Testing

Tagged with

3 Responses to 'TDD: Testing delegation'

Subscribe to comments with RSS or TrackBack to 'TDD: Testing delegation'.

  1. [...] TDD: Testing delegation – Mark Needham talks about the evolution of his testing style when testing delegation based code, looking at how he now perfers stubs to full mocks in this situation [...]

  2. Similarly to what you're saying, I've found interaction-based testing provides the most value in defining/describing an interaction when mocking explicit roles (and hasn't been coded yet). So using mocking to discover roles rather than substitute dependencies is where the real value lies. In light of this in your examples that use partial mocking it makes sense to use a concrete stub instead.

    I'm also starting to think concrete stubs are the way to go as real code is easier to keep up to date than some of the tricks that various testing frameworks use. It depends on how powerful your tools are at to keeping up with changes though. Heres a more extreme view to mull over:

    http://www.pubbitch.org/blog/2006/09/09/rules_of_engagement_for_using_mock_objects

    Matt Dunn

    29 Nov 09 at 12:46 pm

  3. [...] Mark Needham has blogged in the past about using TDD on delegation. However, the post is mostly about unit-testing such objects, not writing the tests first in order [...]

Leave a Reply