Ayende @ Rahien

Refunds available at head office

Advance Mocking with Rhino Mocks 3.5

Here is why I love Rhino Mocks. This is a test that utilize quite a bit of the underlying power of Rhino Mocks. Check this out:

[Test]
public void For_each_batch_from_repository_will_create_and_execute_command()
{
	var stubbedCommand = MockRepository.GenerateMock<ICommand>();
	var mocks = new MockRepository();
	var queueProcessor = mocks.PartialMock<QueueProcessor>(
		stubbedQueueFactory, 
		stubbedOutgoingMessageRepository);

	queueProcessor
		.Stub(x => x.CreateCommand(Arg<SingleDestinationMessageBatch>.Is.Anything))
		.Return(stubbedCommand)
		.Repeat.Any();

	stubbedCommand.Expect(x => x.Execute()).Repeat.Times(3);

	mocks.ReplayAll();

	stubbedOutgoingMessageRepository
		.Stub(x => x.GetBatchOfMessagesToSend())
		.Return(new MessageBatch
		{
			DestinationBatches = new[]
			{
				new SingleDestinationMessageBatch(),
				new SingleDestinationMessageBatch(),
				new SingleDestinationMessageBatch(),
			}
		});

	stubbedOutgoingMessageRepository
		.Stub(x => x.GetBatchOfMessagesToSend())
		.Return(new MessageBatch())
		.Do(delegate { queueProcessor.Stop(); });

	queueProcessor.Run();

	stubbedCommand.VerifyAllExpectations();
}

I use a partial mock to override a single method, use AAA for really nice syntax, the new Do() to allow me to have fine grain control over what is going on and in general mess about with complete control over all the knobs there are.

And just for completion sake, here is the code under test:

public void Run()
{
	while (shouldStop == false)
	{
		checkForMessages.WaitOne(TimeSpan.FromSeconds(1), false);
		MessageBatch messageBatch;
		do // as long as there are messages we don't want to wait
		{
			messageBatch = outgoingMessageRepository.GetBatchOfMessagesToSend();
			foreach (var batch in messageBatch.DestinationBatches)
			{
				ICommand cmd = CreateCommand(batch);
				cmd.Execute();
			}
		} while (messageBatch.IsEmpty == false && shouldStop == false);
	}
}

Sweet!

Comments

Aaron Jensen
07/02/2008 06:13 AM by
Aaron Jensen

You said you "use AAA for really nice syntax", but I don't see that in this test. The new extension methods you added are not AAA in my opinion unless you actually use AssertWasCalled.

The whole point of our push for AAA in a mocking was to move away from setting up expectations in the middle of the test (like you did right before your replay) so that the test would be easier to follow.

Out of curiousity, why is your ReplayAll in the middle of your stubs? Would it be just as functional before the Run()?

I think having to use partial mocks is generally a smell. Most of the time you have to use them it's because you're violating SRP. This is a perfect example of that. I'd consider moving the Command creation into a factory.

The two ordered stubs after the ReplayAll are difficult to follow as well. How about a ThenReturn() method?

foo.Stub(x=>x.Bar()).Return(1).ThenReturn(2);

And no, I can't send a patch for this at this time :)

Ayende Rahien
07/02/2008 06:38 AM by
Ayende Rahien

This test test the interaction, as such, I find it much more natural to use Expect() and verify than to assert on that.

About ThenReturn(2), good idea, but this happen rarely enough that is is not a real concern of mine.

Aaron Jensen
07/02/2008 06:48 AM by
Aaron Jensen

What? I would hope that unless you're testing the interaction you're not going to use Expect OR AssertWasCalled.

How is it more natural to hide the assertion in the middle of the test?

Ayende Rahien
07/02/2008 06:50 AM by
Ayende Rahien

I am not following on the first statment.

For the second, I find it more natural to have an expectation before the interaction

Aaron Jensen
07/02/2008 07:05 AM by
Aaron Jensen

Expect is an Assert.

You should generally be asserting one thing in a test.

If you are asserting that an interaction occurred, you should use Expect/Verify or AssertWasCalled.

If you testing state, you should not use these things, as then you are testing more than one thing in your test.

With regards to your finding Expect/Verify more natural, that's fine, but please don't call it AAA. That will only confuse the issue more than it already is.

I didn't mind Expect/Verify as much as I do now until I started writing context/spec style tests. At that point the AAA syntax became a necessity. Even before then though, I liked being able to look at the bottom of the test and see what should have happened... what I was testing.

Comments have been closed on this topic.