我非常感谢Moq的Loose模拟行为,在没有设定期望时返回默认值.这很方便,可以节省代码,也可以作为一种安全措施:在单元测试期间不会无意中调用依赖关系(只要它们是虚拟的).
但是,当被测方法恰好是虚拟时,我对如何保持这些好处感到困惑.
在这种情况下,我确实想要为这一个方法调用真正的代码,同时仍然对该类的其余部分进行松散的模拟.
我在搜索中找到的就是我可以设置mock.CallBase = true以确保调用该方法.但是,这会影响整个班级.我不想那样做,因为它让我陷入了隐藏调用依赖关系的类中所有其他属性和方法的两难境地:如果CallBase是真的那么我必须要么
我想我想要的是:
mock.Setup(m => m.VirtualMethod()).CallBase();
所以当我打电话时mock.Object.VirtualMethod(),Moq会调用真正的实现......
问:有了Moq,有什么方法可以测试一个虚方法,当我嘲笑这个类只存在几个依赖项时?即不使用CallBase = true并且必须存根所有依赖项?
用于说明的示例代码
(使用MSTest,InternalsVisibleTo DynamicProxyGenAssembly2)
在以下示例中,TestNonVirtualMethod传递但是TestVirtualMethod失败 - 返回null.
public class Foo
{
public string NonVirtualMethod() { return GetDependencyA(); }
public virtual string VirtualMethod() { return GetDependencyA();}
internal virtual string GetDependencyA() { return "! Hit REAL Dependency A !"; }
// [... Possibly many other dependencies ...]
internal virtual string GetDependencyN() { return "! Hit REAL Dependency N !"; }
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestNonVirtualMethod()
{
var mockFoo = new Mock<Foo>();
mockFoo.Setup(m => m.GetDependencyA()).Returns(expectedResultString);
string result = mockFoo.Object.NonVirtualMethod();
Assert.AreEqual(expectedResultString, result);
}
[TestMethod]
public void TestVirtualMethod() // Fails
{
var mockFoo = new Mock<Foo>();
mockFoo.Setup(m => m.GetDependencyA()).Returns(expectedResultString);
// (I don't want to setup GetDependencyB ... GetDependencyN here)
string result = mockFoo.Object.VirtualMethod();
Assert.AreEqual(expectedResultString, result);
}
string expectedResultString = "Hit mock dependency A - OK";
}
Run Code Online (Sandbox Code Playgroud)
Jep*_*sen 14
我相信Lunivore的答案在撰写时是正确的.
在较新版本的Moq中(我认为从2013年开始的4.1版本),您可以使用您提出的确切语法来执行您想要的操作.那是:
mock.Setup(m => m.VirtualMethod()).CallBase();
Run Code Online (Sandbox Code Playgroud)
这将松散的模拟设置为调用基本实现,VirtualMethod而不仅仅是返回default(WhatEver),但VirtualMethod仅限于此成员().
正如用户BornToCode在注释中注释的那样,如果方法具有返回类型void,则这将不起作用.当VirtualMethod非void时,Setup调用给出一个Moq.Language.Flow.ISetup<TMock, TResult>继承CallBase()方法的方法Moq.Language.Flow.IReturns<TMock, TResult>.但是当方法无效时,我们会得到一个Moq.Language.Flow.ISetup<TMock>缺少所需CallBase()方法的方法.
由于没有人多年来回答这个问题,我认为值得回答,我将集中讨论你提出的最高级问题:当被测方法碰巧是虚拟时,如何保持这些好处.
快速回答:你不能用Moq,或者至少不能直接使用Moq.但是,你可以做到.
假设你有两个方面的行为,其中方面A是虚拟的而方面B则不是.这几乎反映了你在课堂上的成就.B可以使用其他方法吗?由你决定.
目前,你的班级Foo正在做两件事 - A和B.我可以说它们是单独的责任,因为你想要模拟A并自己测试B.
您可以:而不是试图模拟虚拟方法而不嘲笑其他任何东西,而不是:
Foo通过Foo的构造函数现在你可以模拟A,并且仍然可以调用B..N的真实代码,而无需实际调用真实的A.你可以保持虚拟或通过接口访问它并模拟它.这也符合单一责任原则.
您可以使用Foo- 使构造函数Foo()调用构造函数Foo(new A())- 级联构造函数- 因此您甚至不需要依赖注入框架来执行此操作.
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
22942 次 |
| 最近记录: |