Rhino Mocks 3.5A feature to be proud of - seamless Do()

time to read 2 min | 384 words

image One of the major pain points for me in Rhino Mocks has always been the Callback() and Do() delegates. I designed them at the 1.1 days, when we didn't have such things as anonymous delegates or lambda. As a result, they required you to explicitly pass a delegate type, where a pain to use and major eye sore.

For a long time, I accepted that there is nothing to do. The fault was with the annoying compiler, and like many other language limitations, you just have to live with it.

I was writing something today and I really want to be able to use Do(), but I had zero intention of getting into that mess again. And suddenly it hit me.

I was doing it all wrong. I should be trying to get the user to do the work, instead of the compiler. Here is the deal, the original design of Do() include matching the called method signature. But most often, you don't care about that.

Once I realized that, I realized that my issue all along was the insistence that it should be strongly typed. There isn't any really reason why this should be so. And once you let go of that, you can get this really cool syntax:

[Test]
public void Can_use_when_called_to_exceute_code_when_exceptation_is_matched_ \
                 without_stupid_delegate_sig_overhead()
{
	var wasCalled = true;
	var stub = MockRepository.GenerateStub<IDemo>();
	stub.Stub(x => x.StringArgString(Arg.Is("")))
		.Return("blah")
		.Do(delegate { wasCalled = true; });
	Assert.AreEqual("blah", stub.StringArgString(""));
	Assert.IsTrue(wasCalled);
}

Oh, and it even allows you to directly modify the method return value:

[Test]
public void Can_modify_return_value()
{
	var wasCalled = true;
	var stub = MockRepository.GenerateStub<IDemo>();
	stub.Stub(x => x.StringArgString(Arg.Is("")))
		.Return("blah")
		.Do(invocation => invocation.ReturnValue = "arg");
	Assert.AreEqual("arg", stub.StringArgString(""));
	Assert.IsTrue(wasCalled);
}

You can also inspect the method arguments and make decisions based on that:

[Test]
public void Can_inspect_method_arguments()
{
	var wasCalled = true;
	var stub = MockRepository.GenerateStub<IDemo>();
	stub.Stub(x => x.StringArgString(null))
		.IgnoreArguments()
		.Return("blah")
		.Do(invocation => Assert.AreEqual("foo", invocation.Arguments[0]));
	Assert.AreEqual("blah", stub.StringArgString("foo"));
	Assert.IsTrue(wasCalled);
}

Overall, this just equaled to the entire AAA syntax in my level of pain reduction.

More posts in "Rhino Mocks 3.5" series:

  1. (30 Jun 2008) Getting closer to conclusion
  2. (29 Jun 2008) The role of Stub vs. Mock
  3. (29 Jun 2008) To be strict or not?