Ayende @ Rahien

Refunds available at head office

The test of fire: Rhino Mocks 3.5 in the real world

imageI have been waiting on the release for Rhino Mocks 3.5, seeing what kind of feedback I can get from users. I also had another reason, I hadn't had the chance to really give it a good testing, in the only manner that matter, using it to develop production ready software.

Here is my latest test, which I am fairly pleased with.

[TestFixture]
public class WebcastControllerTest
{ 
	private WebcastController controller;
	private IRepository<Webcast> repositoryStub;
	private StubEngineContext engineContext;
	private IUnitOfWork unitOfWorkStub;
	private IDisposable disposeGlobalUnitOfWorkRegistration;

	[SetUp]
	public void Setup()
	{
		repositoryStub = MockRepository.GenerateStub<IRepository<Webcast>>();
		unitOfWorkStub = MockRepository.GenerateStub<IUnitOfWork>();
		controller = new WebcastController(repositoryStub)
		             	{
		             		ControllerContext = new ControllerContext{Name = "webcast"},
		             	};
		engineContext = new StubEngineContext();
		controller.SetEngineContext(engineContext);
		disposeGlobalUnitOfWorkRegistration = UnitOfWork.RegisterGlobalUnitOfWork(unitOfWorkStub);
	}

	[TearDown]
	public void TearDown()
	{
		disposeGlobalUnitOfWorkRegistration.Dispose();
	}

	[Test]
	public void When_index_called_will_send_existing_webcasts_to_view()
	{
		var webcasts = new List<Webcast>();
		repositoryStub.Stub(x => x.FindAll()).Return(webcasts);

		controller.Index();

		Assert.AreSame(webcasts, controller.PropertyBag["webcasts"]);
	}

	[Test]
	public void When_display_called_will_send_webcast_to_view()
	{
		var webcast = new Webcast();
		controller.Display(webcast);

		Assert.AreSame(webcast, controller.PropertyBag["webcast"]);
	}

	[Test]
	public void When_edit_called_with_webcast_will_send_webcast_to_view()
	{
		var webcast = new Webcast();
		controller.Edit(webcast);

		Assert.AreSame(webcast, controller.PropertyBag["webcast"]);
	}

	[Test]
	public void When_saving_invalid_webcast_will_redirect_to_edit()
	{
		var webcast = new Webcast();

		controller.Validator.IsValid(webcast);
		controller.PopulateValidatorErrorSummary(webcast, controller.Validator.GetErrorSummary(webcast));

		controller.Save(webcast);

		Assert.Contains(engineContext.MockResponse.RedirectedTo, "edit");
	}

	[Test]
	public void When_saving_invalid_webcast_will_flash_error_summary_and_webcast_in_flash()
	{
		var webcast = new Webcast();

		controller.Validator.IsValid(webcast);
		controller.PopulateValidatorErrorSummary(webcast, controller.Validator.GetErrorSummary(webcast));

		controller.Save(webcast);

		Assert.AreSame(webcast, controller.Flash["webcast"]);
		Assert.AreSame(controller.Validator.GetErrorSummary(webcast), controller.Flash["errorSummary"]);
	}

	[Test]
	public void When_saving_valid_webcast_will_redirect_to_display()
	{
		var webcast = new Webcast();

		// explicitly not calling validation, the controller will assume 
		// that this is a valid object

		controller.Save(webcast);

		Assert.Contains(engineContext.MockResponse.RedirectedTo, "display");
	}

	[Test]
	public void When_saving_valid_webcast_will_save_and_flash_unit_of_work()
	{
		var webcast = new Webcast();

		// explicitly not calling validation, the controller will assume 
		// that this is a valid object

		controller.Save(webcast);

		repositoryStub.AssertWasCalled(x=>x.Save(webcast));
		unitOfWorkStub.AssertWasCalled(x=>x.TransactionalFlush());
	}
}

Comments

Chris Brandsma
06/13/2008 03:25 AM by
Chris Brandsma

that looks really nice.

I'll start playing with it next week.

Ryan Montgomery
06/13/2008 11:48 AM by
Ryan Montgomery

It's great to see lambda support with Rhino Mocks. I started looking at Moq because of the tight integration with some of the new c# features, and lambda expressions seem to be a very intuitive approach to mocking. Very nice job as always!

Alexander Gro&#223;
06/13/2008 02:00 PM by
Alexander Groß

Ayende,

Comparing the test fixture implementation to the one in your article "Answer:How many tests?" shows that you do not inherit from DatabaseTestFixtureBase any more.

When is it recommended to inherit from DatabaseTestFixtureBase and why did you choose not to inherit this time?

Thanks,

Alex

Ayende Rahien
06/13/2008 02:23 PM by
Ayende Rahien

This test doesn't use a database, it is completely in memory one.

Andre Loker
06/28/2008 11:54 AM by
Andre Loker

Hi Oren,

First of all, the new syntax looks and feels nice!

I have two questions:

1) I noticed that in none of the tests you're setting up any expectations, everything is stubbing only. Is this a coincidence just for these tests or would you generally recommend less mocking (in the sense of setting expectations) and more stubbing?

2) GenerateStub and GenerateMock create a new MockRepository on every call. In the case of mocks with expectations I would need to vall VerifyAllExpectations() on every mock. I actually liked mockRepository.VerifyAll() which won't work with mocks created with GenerateMock. Will there be equivalent instance methods in Rhino Mock 3.5 RMT that do the same as GenerateStub/GenerateMock (ie. call Stub/DynamicMock on the MockRepository and set them in Replay mode directly)?

Regards,

Andre

Ayende Rahien
06/28/2008 04:21 PM by
Ayende Rahien

Stubs are generally more useful than mocks.

You should have a single mock object in each your test, no more.

The lack of VerifyAll() goes back to needing only a single mock object per test.

Andre Loker
06/28/2008 04:37 PM by
Andre Loker

So the general case would be to use stubs. Only unit tests that really test for interoperation between the SUT and it's dependencies should use mocks, one at a time. Sounds reasonable, thanks!

Comments have been closed on this topic.