Search code examples
c#asp.net-mvcunit-testingrhino-mocks

RhinoMock - Use a real object, but stub a single method


I'm writing a unit test against an MVC Controller that has a dependency on IFoo. Foo (the implementation) has one method I'd like to stub, but I want to leave the other intact. How can I set this up using RhinoMock?

Foo has several dependencies that I'd prefer not to mock to save writing additional lines of code and cluttering my test.

Foo :

public interface IFoo{
    int Method1();
    int Method2();
}

public class Foo : IFoo{
   //lot's of dependencies
   public Foo(IBar bar, IBaz baz, IStackOverflow so){}
}

Test:

[Test]
public void What_I_Have_So_Far(){
    //arrange
    //load the real IFoo from Ninject (DI)
    var mockFoo = new Ninject.Kernel(new MyExampleModule())
                    .Get<IFoo>();

    //I want this test to use the real Method1, but not Method2
    //so stub Method2
    mockFoo
       .Stub(x => x.Method2()) //<---- blows up here
       .Returns(42);

    //act
    var controllerUnderTest = new Controller(mockFoo);

Error:

Using this approach, RhinoMock throws an Exception:

System.InvalidOperationException : The object 'MyApplication.MyExampleModule' is not a mocked object.

Question:

How can I stub method2?

I know I could create IFoo as a mock via MockRepository.GenerateMock, but then'd I'd have to copy the real implementation of Method1.


Update:

Both Brad and Jimmy's solution seam to work equally well, I picked Brad's only because it was less code to write.

However, after researching this a bit further, it looks like what I need is an AutoMocker. There seams to be one for StructureMap and Moq, but not RhinoMocks: https://github.com/RhinoMocks/RhinoMocks/issues/3


Solution

  • You have to do it the other way around. Create mocked IFoo and redirect some calls to real IFoo (this has to be done via WhenCalled extension):

    var realFoo = new Ninject.Kernel(new MyExampleModule()).Get<IFoo>();
    var mockFoo = MockRepository.GenerateStub<IFoo>();
    
    mockFoo.Stub(f => f.Method2()).Return(42);
    mockFoo.Stub(f => f.Method1())
       .WhenCalled(invocation =>
       {
           invocation.ReturnValue = realFoo.Method2();
       })
       .Return(whateverValue);
    

    The final Return is required even though we override it few lines before. Otherwise Rhino will throw exception.