RhinoMock - 使用真实对象,但存根一个方法

时间:2015-06-02 23:50:43

标签: c# asp.net-mvc unit-testing rhino-mocks

我正在针对依赖IFoo的MVC控制器编写单元测试。 Foo(实现)有一种我想要存根的方法,但我想保留其他方法。如何使用RhinoMock

进行设置

Foo有几个依赖项,我更喜欢而不是来模拟以节省编写额外的代码行并使我的测试混乱。

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]
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);

错误:

使用这种方法,RhinoMock会抛出异常:

  

System.InvalidOperationException:对象&#39; MyApplication.MyExampleModule&#39;不是一个嘲弄的对象。

问题:

如何存根method2

我知道我可以通过IFoo创建MockRepository.GenerateMock作为模拟,但是之后我必须复制Method1的真实实现。

更新

Brad和Jimmy的解决方案同样适用,我选择Brad只是因为写代码较少。

然而,在进一步研究之后,看起来我需要的是AutoMocker。接缝是StructureMapMoq的接缝,但不是RhinoMocks:https://github.com/RhinoMocks/RhinoMocks/issues/3

3 个答案:

答案 0 :(得分:1)

你必须以相反的方式做到这一点。创建模拟IFoo并将某些调用重定向到真实IFoo(这必须通过WhenCalled扩展名完成):

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);

最后Return是必需的,即使我们之前覆盖了几行。否则Rhino会抛出异常。

答案 1 :(得分:1)

由于需要最少量的“侵入式”工作,我会考虑使用适配器模式。所以,我们有原始的界面和具体的类:

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

public class Foo : IFoo
{
    public void Method1()
    {
        Console.WriteLine("I am Method1 of Foo");
    }
    public void Method2()
    {
        Console.WriteLine("I am Method2 of Foo");
    }
}

用于单元测试的单个实现:

public class FooAdapter : IFoo
{
    private readonly IFoo foo;

    public FooAdapter(IFoo foo)
    {
        this.foo = foo;
    }

    public void Method1()
    {
        this.foo.Method1();
    }

    public void Method2()
    {
        Console.WriteLine("I am Method2 of FooAdapter");
    }
}

该类可以是单元测试类的本地类,只需定义为:

IFoo foo = new FooAdapter(kernel.Get<IFoo>());

我同意你的意见,更改基本代码以满足单元测试并不是正确的选择。单元测试应该随便坐在上面,永远不要反向探测他们所针对的代码。

答案 2 :(得分:1)

  

然而,在进一步研究之后,它看起来像我   需要的是一个AutoMocker。有接缝是StructureMap和Moq的接缝,   但不是RhinoMocks:https://github.com/RhinoMocks/RhinoMocks/issues/3

我没有深入研究过,但我知道CodePlex上的AutoMock项目。也许这就是答案?

功能

  • 通过基于构造函数的依赖注入,为正在测试的任何依赖于一组依赖关系的类动态创建模拟/存根。
  • 目前支持RhinoMocks。

https://automock.codeplex.com/