RhinoMock - 使用一个真实的对象,但存根一个单一的方法
RhinoMock - Use a real object, but stub a single method
我正在针对依赖于 IFoo
的 MVC 控制器编写单元测试。 Foo
(实现)有一种方法我想存根,但我想保持另一种不变。如何使用 RhinoMock
?
进行设置
Foo
有几个依赖项,我更喜欢 而不是 来模拟以节省编写额外的代码行和使我的测试混乱。
富:
public interface IFoo{
int Method1();
int Method2();
}
public class Foo : IFoo{
//lot's of dependencies
public Foo(IBar bar, IBaz baz, IWhosebug 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 : The object 'MyApplication.MyExampleModule' is not a mocked object.
问题:
我如何存根 method2
?
我知道我可以通过 MockRepository.GenerateMock
创建 IFoo
作为模拟,但是我必须复制 Method1
的真实实现。
更新:
Brad 和 Jimmy 的解决方案都可以很好地工作,我选择 Brad 的只是因为它需要编写的代码更少。
然而,在进一步研究之后,看起来我需要的是一个 AutoMocker。 StructureMap and Moq, but not RhinoMocks: https://github.com/RhinoMocks/RhinoMocks/issues/3
有一条缝
你必须反过来做。创建模拟 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 会抛出异常。
只要付出最少的 "invasive" 努力,我就会考虑使用适配器模式。所以,我们有我们原来的界面和具体 class:
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");
}
}
class 可能是单元测试 class 的局部,简单定义为:
IFoo foo = new FooAdapter(kernel.Get<IFoo>());
我同意你的看法,改变你的基本代码以满足单元测试不是正确的道路。单元测试应该随便放在上面,永远不要反向插入到它们所针对的代码中。
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
我没有深入研究,但我知道 CodePlex 上的 AutoMock 项目。也许这就是答案?
特征
- 通过基于构造函数的依赖项注入,为任何依赖于一组依赖项的被测class动态创建mocks/stubs。
- 目前支持 RhinoMocks。
我正在针对依赖于 IFoo
的 MVC 控制器编写单元测试。 Foo
(实现)有一种方法我想存根,但我想保持另一种不变。如何使用 RhinoMock
?
Foo
有几个依赖项,我更喜欢 而不是 来模拟以节省编写额外的代码行和使我的测试混乱。
富:
public interface IFoo{
int Method1();
int Method2();
}
public class Foo : IFoo{
//lot's of dependencies
public Foo(IBar bar, IBaz baz, IWhosebug 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 : The object 'MyApplication.MyExampleModule' is not a mocked object.
问题:
我如何存根 method2
?
我知道我可以通过 MockRepository.GenerateMock
创建 IFoo
作为模拟,但是我必须复制 Method1
的真实实现。
更新:
Brad 和 Jimmy 的解决方案都可以很好地工作,我选择 Brad 的只是因为它需要编写的代码更少。
然而,在进一步研究之后,看起来我需要的是一个 AutoMocker。 StructureMap and Moq, but not RhinoMocks: https://github.com/RhinoMocks/RhinoMocks/issues/3
有一条缝你必须反过来做。创建模拟 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 会抛出异常。
只要付出最少的 "invasive" 努力,我就会考虑使用适配器模式。所以,我们有我们原来的界面和具体 class:
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");
}
}
class 可能是单元测试 class 的局部,简单定义为:
IFoo foo = new FooAdapter(kernel.Get<IFoo>());
我同意你的看法,改变你的基本代码以满足单元测试不是正确的道路。单元测试应该随便放在上面,永远不要反向插入到它们所针对的代码中。
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
我没有深入研究,但我知道 CodePlex 上的 AutoMock 项目。也许这就是答案?
特征
- 通过基于构造函数的依赖项注入,为任何依赖于一组依赖项的被测class动态创建mocks/stubs。
- 目前支持 RhinoMocks。