Search code examples
c#unit-testingrhino-mocks

How to set a default return value in a Rhino Mocks stub


Say I want to use Rhino Mocks to generate a stub of the following interface:

public interface IFooBar
{
  string Foo(string bar);
}

I stub the method Foo in the one-time setup method for my suite of unit tests, along with the following constraints:

  var foobar = MockRepository.GenerateStub<IFooBar>();
  foobar.Stub(f => f.Foo(Arg<string>.Is.Equal("string1")))
    .Repeat.Any()
    .Return("result1");
  foobar.Stub(f => f.Foo(Arg<string>.Is.Equal("string2")))
    .Repeat.Any()
    .Return("result2");
  //etc...

Currently, if the parameter bar doesn't match any of the constraints above, the method Foo will return null by default. Is there some way I can tell it to return something other than null in these cases (e.g. an empty string or some other arbitrary string)?

I've tried searching the documentation, SO, and elsewhere online but haven't yet found a solution that does what I want.

I tried adding this to the beginning, hoping the subsequent calls to foobar.Stub would "override" this default behavior when the more specific constraints were satisfied:

  foobar.Stub(f => f.Foo(Arg<string>.Is.Anything))
    .Repeat.Any()
    .Return(string.Empty);

Unfortunately that isn't the case; adding the above causes Foo to always return an empty string, as if none of the other Foo.Stub calls ever happened.

I could do the opposite and make the above call after all the other Foo.Stub calls, effectively covering all the remaining possible cases. The downside to this approach is once I do that, I can no longer add any other constraints that may be specific to one particular unit test but not any others.

Worst case scenario, I can extract all the common Foo.Stub calls into a reusable method to call at the beginning of each unit test, followed by more test-specific stubs, and finally the above stub that covers the remaining cases. I'm just wondering if there's a simpler solution.


Solution

  • Provide a Method Implementation using the input parameters

    Instead of using a .Return() with a simple value, you can provide a full implementation of the method using the .Do() method. This also allows you to get access to the input parameters. If you want, you can define a delegate and just call the delegate.

    For example

    //Arrange
    var foobar = MockRepository.GenerateStub<IFooBar>();
    foobar.Stub(_ => _.Foo(Arg<string>.Is.Anything))
      .Repeat.Any()
      .Do((Func<string, string>)(input => {
          if (input == "string1") {
              return "result1";
          } else if (input == "string2") {
              return "result2";
          }
          return string.Empty; // or some other arbitrary string
      }));
    
    //Act & Assert to prove it works (using FluentAssertions)
    foobar.Foo("string1").Should().Be("result1");
    foobar.Foo("string2").Should().Be("result2");
    foobar.Foo(null).Should().Be(string.Empty); // or some other arbitrary string