6

I highly appreciate anyone can help me in below-mentioned issue: I've been using RhinoMock in Unit Test. I define my mock object in such manner, with sessionToken is string-typed:

mockRepository.Stub(repository => repository.FindById(sessionToken)).Return(new DeviceTypeRepository().NewTable(false));

It's ok for the code section when calling FindById() to return the valid new new DeviceTypeRepository().NewTable(false);

However, when include a complex parameter as object, such as a DataTable, into the Stub as below:

mockRepository.Stub(repository => repository.Find(sessionToken, dataTable)).Return(new DeviceTypeRepository().NewTable(false));

Then the code section in which Find() is invoked, it does NOT return expected new DeviceTypeRepository().NewTable(false). Notice that input value of parameter dataTable is the same in both Stub and in Find() invocation.

Hence, my question is: How could I implement such parameter (DataTable typed and more generally) into Stub initialization using RhinoMock ? I'd be grateful to any advice and approach. Thanks

Undefined Identity
  • 475
  • 3
  • 7
  • 16

2 Answers2

9

I believe the problem is not in a complex datatype but rather in the expectations you've set.

As a first attempt to fix it, add IgnoreArguments() before the Return. It could be that DataTable you've specified in expectation differs from the actually-passed-in DataTable instance so expectations won't pass:

...Stub(...).IgnoreArguments().Return();

If not helped you can debug it manually using WhenCalled():

...Stub(...).IgnoreArguments().WhenCalled(
    mi => 
    {
        var token = mi.Arguments[0] as TokenDataType;
        var dataTable = mi.Arguments[1] as DataTable;
    }).Return();

If that doesn't help, try to add Repeat().Any() after the Return() and see whether it works. I am supposing that if the method was called a few times, you may have missed the first return value, but I may be wrong.

ErikE
  • 48,881
  • 23
  • 151
  • 196
sll
  • 61,540
  • 22
  • 104
  • 156
  • I liked the WhenCalled usage. However, with Stub you wouldn't need to add Repeat().Any(), it's the default behavior. – Amittai Shapira Oct 14 '11 at 19:36
  • @Amittai Shapira : good point, thanks, any reference to documentation? I mostly using Mock and for mock it does not repeat by default – sll Oct 14 '11 at 19:46
  • 1
    Thank you for asking for evidence. I was wrong :-( the behavior of mocks and stubs in this case is similar, the default is Repeat().Once(): http://groups.google.com/group/rhinomocks/browse_thread/thread/03aff4992b5607cb – Amittai Shapira Oct 14 '11 at 20:13
  • I had the same issue and by adding .IgnoreArguments().Return it sorted me out. Thanks!! – Steve May 28 '12 at 10:05
6

If it doesn't return what you'd expect, then the parameters between the stub call and the actual call don't match. Let's say you have something like this:

// Set expectations
var someDataTable = new DataTable(columns, raws);
mockRepository
   .Stub(repository => repository.Find(sessionToken, dataTable))
   .Return(new DeviceTypeRepository().NewTable(false));

// Actual test
var anotherDataTable = new DataTable(columns, raws);
yourTestObject.DoSomethingThatLooksForTheDataTable(repository);

The thing here that even though the someDataTable and anotherDataTable have the exact same content, they're not the same object and when RhinoMocks compare the stub call to the actual call the parameters don't match. What you can do is use constraints:

mockRepository
   .Stub(repository => repository.Find(
      Arg<SessionID>.Matches(y => y.ID == 2),
      Arg<DataTable>.Matches(x => x.Columns == columns && x.Raws == raws)
   ))
   .Return(true);
ErikE
  • 48,881
  • 23
  • 151
  • 196
Amittai Shapira
  • 3,749
  • 1
  • 30
  • 54
  • Is there any other way to use Contraints of RhinoMock ? Something alike: mockRepository.Stub(repository => repository.Find(..., ...)).Contraints(Is.EqualTo(x), ...) – Undefined Identity Oct 20 '11 at 03:53