我有一个测试,我通过了一个对象,如下所示:
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();
不太确定这是否有用,但如果要模拟的方法是虚拟,则可以部分模拟对象。
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());
}
如果使用同一个对象,则不能对Moq执行此操作,除非其中一个方法是虚拟的,并且您的mock基于类型而非接口。
这是因为当你传递一个基于接口的模拟对象时,你没有传递一个真实的对象,所以它不能访问对象的真实方法。
您正在传递一个动态代理,该代理将响应已设置为响应的方法。
我相信TypeMock会在运行时重写程序集来实现这一点,这是Moq绝对不会做的
如果你想用Moq:获得类似的结果
- 您可以模拟这两种方法
- 您必须将这两个方法提取到不同的依赖项,以便模拟一个依赖项而不是另一个
- 你可以把你需要的方法模拟成虚拟的,这将是我更喜欢的解决方案
编辑:我在阅读AlanT的答案后编辑了我的答案以确保正确。