我正在做一些单元测试,并使用 Moq 模拟一些属性。
现在,这是一个 Controller 测试 (ASP.NET MVC 3)。我的 Controller 派生自一个名为 AbstractController 的抽象 Controller 。
此 Controller 依赖于 Http 上下文(以便执行诸如主题化、基于 HTTP HOST header 的域特定逻辑等操作)。
这是通过名为 WebSiteSettings 的属性完成的:
public abstract class AbstractController : Controller
{
public WebSiteSettings WebSiteSettings { get; private set; }
// other code
}
注意私有(private)集——ctor 设置它。所以,我将其更改为使用一个界面,这就是我所 mock 的:
public IWebSiteSettings WebSiteSettings { get; private set; }
然后我创建了一个“FakeWebSiteSettings”,它模拟 Http 上下文以便它读取 HTTP header 。
问题是,当我运行测试时,我得到一个NotSupportedException:
Invalid setup on a non-virtual (overridable in VB) member: x => x.WebSiteSettings
这是相关的模拟代码:
var mockWebSiteSettings = new Mock<FakeWebSiteSettings>();
var mockController = new Mock<MyController>(SomeRepository);
mockController.Setup(x => x.WebSiteSettings).Returns(mockWebSiteSettings.Object);
_controller = mockController.Object;
var httpContextBase = MvcMockHelpers.FakeHttpContext();
httpContextBase.Setup(x => x.Request.ServerVariables).Returns(new NameValueCollection
{
{"HTTP_HOST","localhost.www.mydomain.com"},
});
_controller.SetFakeControllerContext(httpContextBase.Object);
如果我将 WebsiteSettings
属性设为虚拟 - 测试通过。
但我不明白为什么我需要这样做。我实际上并没有覆盖该属性,我只是在 mock 它的设置方式。
我是不是遗漏了什么,或者做错了什么?
最佳答案
Moq 和其他类似的模拟框架只能模拟接口(interface)、抽象方法/属性(在抽象类上)或虚拟方法/属性在具体类上。
这是因为它会生成一个代理,该代理将实现接口(interface)或创建一个派生类来覆盖那些可覆盖的方法以拦截调用。
关于c# - 为什么我要模拟的属性需要是虚拟的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5670902/