views:

366

answers:

2

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?

A: 

Have you tried using partial mocks with Rhino Mocks as described here. I think if you do that then you will get what you want.

AutomatedTester
Using partial mocks are a very BAD idea: They should only be used if you need to mock something that does not have an interface and is not under your control - in other words if you are quite desperate.
Stefan Steinegger
I never said that it was a good idea. it was an idea for a problem that he was having. So what's your better idea?
AutomatedTester
+2  A: 

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.

Stefan Steinegger
Thanks for the tip and link. So there's no way for me to do it with setting an expectation with arguments, and a stub with "everything else"?Since I use .NET 2.0 on VS2005, I can't use lambda and extension methods, which make it all so much more ugly, I'd like to minimize the usage.
Noam Gal
You can use the old syntax. I try to add it to the answer.
Stefan Steinegger
At the moment I do use the AAA syntax. I just use RhinoMocksExtensions.Stub(dal, delegate<IDal d){ return d.GetDataSet(Args<int>.Is.Anything); }).Return(new DataSet());But I think I'll just make the dal always stub the method, and then add the expectation as an "AssertWasCalled" like you suggested.Thanks again.
Noam Gal