将Moq模拟对象传递给构造函数

70

我已经使用RhinoMocks有一段时间了,但刚开始研究Moq。我遇到了这个非常基本的问题,令我惊讶的是它并不能直接解决。假设我有以下类定义:

public class Foo
{
    private IBar _bar; 
    public Foo(IBar bar)
    {
        _bar = bar; 
    }
    ..
}

现在我有一个测试,需要 Mock 发送给 Foo 的 IBar。在 RhinoMocks 中,我可以简单地像下面这样做,它可以正常工作:

var mock = MockRepository.GenerateMock<IBar>(); 
var foo = new Foo(mock); 

然而,在Moq中,这个方法似乎并不像同样的方式工作。我正在按照以下方式进行:

var mock = new Mock<IBar>(); 
var foo = new Foo(mock); 

然而,现在它失败了 - 告诉我“无法将'Moq.Mock'转换为'IBar'。我做错了什么? 使用Moq进行这样的操作的推荐方法是什么?

3个回答

142

你需要传递模拟对象的实例

var mock = new Mock<IBar>();  
var foo = new Foo(mock.Object);

您还可以使用模拟对象来访问实例的方法。

mock.Object.GetFoo();

Moq文档


但是我需要mock.Object只在调用foo.Object时初始化。我基本上要找的是能够将原始的Mock<IBar>传递给Foo的构造函数,在调用mock.Object时被调用的能力。有没有办法实现这个? - Shimmy Weitzhandler

27
var mock = new Mock<IBar>().Object

只為您提供翻譯內容,不進行解釋:+1 給您,因為您的回答只比被接受的答案晚了 10 秒。謝謝! - stiank81
3
通常我不会像这样将对象实例分配给变量,因为您可能希望为特定行为设置模拟。 - skyfoot
这只是为了展示.Object,它是他遇到的运行时错误的解决方案 :-) - Massimiliano Peluso

2

前面的答案是正确的,但为了完整起见,我想再添加一种方法。使用moq库的Linq功能。

public interface IBar
{
    int Bar(string s);

    int AnotherBar(int a);
}

public interface IFoo
{
    int Foo(string s);
}

public class FooClass : IFoo
{
    private readonly IBar _bar;

    public FooClass(IBar bar)
    {
        _bar = bar;
    }

    public int Foo(string s) 
        => _bar.Bar(s);

    public int AnotherFoo(int a) 
        => _bar.AnotherBar(a);
}

您可以使用Mock.Of<T>来避免调用.Object
FooClass sut = new FooClass(Mock.Of<IBar>(m => m.Bar("Bar") == 2 && m.AnotherBar(1) == 3));
int r = sut.Foo("Bar"); //r should be 2
int r = sut.AnotherFoo(1); //r should be 3

或者使用匹配器。
FooClass sut = new FooClass(Mock.Of<IBar>(m => m.Bar(It.IsAny<string>()) == 2));
int r = sut.Foo("Bar"); // r should be 2

我该如何在模拟定义中指定多个方法/参数?类似于new FooClass(Mock.Of<IBar>(m => m.Bar("Bar") == 2, k => k.Ready() == true ));这样的写法。 - ulkas
@ulkas 你应该使用 &&,我已经更新了答案,FooClass(Mock.Of<IBar>(m => m.Bar("Bar") == 2 && m.Ready() == true )); - Johnny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接