C# – mixing stubs and mocks in rhino

cmockingrhino-mocks

My test is trying to assert that a certain dal method was called, with some parameters.
The method is returning a DataSet object, so my mock just returns an empty DataSet when called.

The problem I have is that when the SUT doesn't call the dal with the proper parameters, the mock will not return the empty DataSet, and so my class will throw an exception on trying to access a null reference. This just causes the test to fail with an unrelated message in my test runner.

I'd like to stub the method to return the empty Dataset in all cases, so the method will run properly, and at the end of the test verify that it was called with the expected parameters. am I asking for too much?

Best Answer

This should do it, assuming that your method has an int argument.

IDal dalMock = MockRepository.GenerateMock<IDal>();

// setup mock to return the emptyDataSet for any argument    
dalMock
  .Stub(x => x.GetDataSet(Arg<int>.Is.Anything))
  .Return(emptyDataSet)
  .Repeat.Any();

sut.Execute()

// assert that the argument had been 7
dalMock.AssertWasCalled(x => x.GetDataSet(Arg<int>.Is.Equal(7))

Documentation of argument constraints. (I wrote this chapter, so you can ask me if you don't understand ;-)


Using .NET 2.0 it would look something like this:

MockRepository mocks = new MockRepository();
IDal dalMock = mocks.CreateDynamicMock<IDal>();

// expect the correct argument
Expect.Call(dalMock.GetDataSet(Arg<int>.Is.Equal(7)))
  .Return(emptyDataSet)
  .Repeat.Once();

// setup mock to return the emptyDataSet for any argument    
SetupResult.For(dalMock.GetDataSet(Arg<int>.Is.Anything))
  .Return(emptyDataSet)
  .Repeat.Any();

sut.Execute()

// assert that the argument had been 7
mocks.VerifyAll();

Not 100% sure if it works, but it should.

You can also try this:

// setup mock to return the emptyDataSet for any argument    
SetupResult.For(dalMock.GetDataSet(Arg<int>.Is.Anything))
  .Do((GetDataSetDelegate)delegate(int i)
    {
      Assert.AreEqual(7, i);
    }
  .Return(emptyDataSet)
  .Repeat.Any();

sut.Execute()

Do is executed when the mock is called. It requires a delegate with the exact same interface as the mocked method. Because of syntactical reasons of .NET 2.0, you need to cast it to the right delegate type, so you need to declare it first (GetDataSetDelegate in this case).

Note for Rhino 3.5 users: there is a much more convenient way to be called: WhenCalled just takes a lambda as argument, but has to be implemented differently.

With Do or WhenCalled respectively you can implement argument assertions when the mock is called.