如何设置Moq以执行Moq中的一些方法

3

我有一个测试,我会传递一个对象,例如:

var repo = new ActualRepo();

var sut = new Sut(repo);

在我的测试中,Repo有一个我需要实际执行的方法,而另一个方法我想要模拟并且不执行。
例如,看下这段伪代码:
var repo = new Mock<IRepo>();

repo.Setup(m => m.MethodIWantToCall()).WillBeExecuted();
repo.Setup(m => m.MethodIWantToMock()).Returns(false);

使用 Moq,这是否可能并且如何实现?
编辑: 我以前使用过 TypeMock,您可以执行以下操作。
Isolator.When(() => repo.MethodToIgnore()).WillBeIgnored();
Isolator.When(() => repo.MethodToActuallyRun()).WillBeExecuted();
2个回答

5
我不确定问题是否有用,但如果您想要mock的方法是virtual的话,则可以部分mock一个对象。
public class Foo {
    public string GetLive() {
        return "Hello";
    }

    public virtual string GetMock() {
        return "Hello";
    }
}

public class Snafu {
    private Foo _foo;
    public Snafu(Foo foo) {
      _foo = foo;
    }

    public string GetMessage() {
        return string.Format("{0} {1}", _foo.GetLive(), _foo.GetMock());
    }
}


[TestMethod]
public void NotMocked() {
    var snafu = new Snafu(new Foo());
    Assert.AreEqual("Hello Hello", snafu.GetMessage());
}


[TestMethod]
public void Mocked() {

    var mockFoo = new Mock<Foo>();
    mockFoo.Setup(mk => mk.GetMock()).Returns("World");

    var snafu = new Snafu(mockFoo.Object);

    Assert.AreEqual("Hello World", snafu.GetMessage());
}

好的,有趣的想法。让我花点时间研究一下,我忘记了虚方法的方法。 - Jason Evans
看起来这个答案比我的更好。我不知道你可以这样做。 - Gilles

3
如果您使用相同的对象,则无法使用Moq做到这一点,除非其中一个方法是虚拟的,并且您基于类型而不是接口构建模拟。这是因为当您传递基于接口的模拟对象时,您并未传递真实对象,因此它无法访问对象的真实方法。您正在传递一个动态代理,它将响应已设置好的方法。我认为TypeMock在运行时重写程序集以实现此目的,Moq绝对不会这样做。如果您想使用Moq实现类似的结果:您可以模拟两种方法,您必须将两种方法提取到不同的依赖项中,以便模拟一个依赖项而不是另一个依赖项。您可以使您需要模拟的方法为虚拟方法,这是我更喜欢的解决方案。 编辑:阅读AlanT的答案后,我编辑了我的答案以获得正确性。

我也有这个怀疑,只是需要从别人那里听到确认一下 :) - Jason Evans
@JasonEvans:这个,以及能够模拟“所有东西”(不仅仅是抽象类或接口)的能力,是我经常看到人们在Moq中找不到的两个特性。 - Gilles

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