Mark Needham

Thoughts on Software Development

TDD: Simplifying a test with a hand rolled stub

with 6 comments

I wrote a couple of weeks ago about my thoughts on hand written stubs vs framework generated stubs and I noticed an interesting situation where it helped me out while trying to simplify some test code.

The code in question was making use of several framework generated stubs/mocks and one in particular was trying to return different values depending on the value passed as a parameter.

The test was failing and I spent about half an hour unsuccessfully trying to work out why it wasn’t working as expected before I decided to replace it with a hand rolled stub that did exactly what I wanted.

This is a simplified version of the test:

[Test]
public void SomeTest()
{
	var service = MockRepository.GenerateStub<IService>();
 
	service.Stub(x => x.SomeMethod("call1")).Return("aValue");
	service.Stub(x => x.SomeMethod("call2")).Return("anotherValue");
 
	// and so on
 
	new SomeObject(service).AnotherMethod();
 
       // some assertions
}

For the sake of the test I only wanted ‘service’ to return a value of ‘aValue’ the first time it was called and then ‘anotherValue’ for any other calls after that.

I therefore wrote the following hand rolled stub to try and simplify the test for myself and plugged it into the original test:

public class AValueOnFirstCallThenAnotherValueService : IService
{
	private int numberOfCalls = 0;
 
	public string SomeMethod(string parameter)
	{
		if(numberOfCalls == 0)
		{
			numberOfCalls++;
			return "aValue";
		}
		else
		{
			numberOfCalls++;
			return "anotherValue";
		}
	}
}
[Test]
public void SomeTest()
{
	var service = new AValueOnFirstCallThenAnotherValueService();
 
	new SomeObject(service).AnotherMethod();
 
       // some assertions
}

I’ve never tried this particular approach before but it made it way easier for me to identify what was going wrong and I was then able to get the test to work as expected and move onto the next one.

In retrospect it should have been possible for me to work out why the original framework generated stub wasn’t working but it seemed like the right time to cut my losses and the time to write the hand generated one and get it working was an order of magnitude less.

Written by Mark Needham

January 25th, 2010 at 9:23 pm

Posted in Testing

Tagged with

  • Pingback: Tweets that mention TDD: Simplifying a test with a hand rolled stub at Mark Needham -- Topsy.com

  • http://blog.dotnetwiki.org Peli

    Hi Mark,

    The manual mock approach works great here because the IService interface has a single method. If that interface would have many methods, you would end up with a lot of ‘not implemented’ methods. This is typically why one would use a mock framework.

    Now the shameless plug: if you would use the Stubs farmework that ship with Pex, you would have almost the same experience as with manual mocks, without having to dangling ‘not implemented’ methods lying around. In a nutshell, Stubs allows you to replace any method of the interface with your delegate, e.g. your example would look like this:

    [TestMethod]
    void SomeTest() {
    int numberOfCalls = 0;
    var service = new SIService { // implements IService
    SomeMethodString = s => { // Func
    if(numberOfCalls++ == 0)
    return “aValue”;
    else
    return “another value”;
    }
    };
    … // the rest of the test
    }

    Stubs is really just a code generator that produces the SIService type that has a delegate field and a boiler plate implementation for each method:

    class SIService : IService {
    public Func SomeMethodString;
    string IService.SomeMethod(string s) {
    var f = this.SomeMethodString;
    if (f != null) return f(s);
    else throw Exception();
    }
    }

  • http://andypalmer.com Andy Palmer

    Why did you choose to count calls, rather than use a boolean firstCall?

  • http://www.markhneedham.com Mark Needham

    Didn’t think of that, good shout – that’d be much simpler.

  • http://www.clear-lines.com/blog Mathias

    Intriguing issue, got me to dig in the Rhino.Mocks documentation to see if I could find anything there. The best I could come up with was the following:
    var fake = MockRepository.GenerateStub();
    fake.Expect(f => f.Method(null)).IgnoreArguments().Return(“First”).Repeat.Once();
    fake.Expect(f => f.Method(null)).IgnoreArguments().Return(“Second”);
    var first = fake.Method(“ABC”);
    var second = fake.Method(“DEF”);
    Assert.AreEqual(“First”, first);
    Assert.AreEqual(“Second”, second);
    It seems that it’s doing what you are trying to do. That being said, arguably, the hand-rolled version is clearer :)

  • miluch

    The smart recording of expectation on mocks was introduced a long time ago to the most popular java mocking frameworks (easyMock, mockito, jmock).This fact along with “not-implemented” experience (as stated in the first comment) do not convince me to write own stubs instead of let framework generate ones.