2013-01-22 45 views
1

我似乎无法使用Moq来模拟HttpContext.Request.Url.Authority,因为它是一种非虚拟方法。我收到以下例外情况:Moq - 我如何嘲笑像HttpContext.Request.Url.Authority对象的非虚拟成员?

{"Invalid setup on a non-virtual (overridable in VB) member: p => p.HttpContext.Request.Url.Authority"} 

我该如何克服这一点?下面是我的测试方法:

[TestMethod] 
public void ForgottenPasswordPost_Requested_CaptchaCorrectEmailExists() 
{ 
    _testModel.ControllerContext.SetupGet(p => p.HttpContext.Session["Captcha"]).Returns("HelloWorld"); 
    _testModel.ControllerContext.SetupGet(p => p.HttpContext.Request.Url.Authority).Returns("www.localhost.com"); 
    _testModel.QMember.Setup(m => m.MemberExistsWithEmail(It.IsAny<string>())).Returns(true); 


    var controllerUnderTest = _testModel.ReturnController(); 
    ForgottenPasswordModel model = new ForgottenPasswordModel() { Captcha = "HelloWorld" }; 

    //Act 
    var actionResult = (RedirectToRouteResult)controllerUnderTest.ForgottenPassword(model); 

    Assert.AreEqual("ForgottenPasswordConfirm", actionResult.RouteValues["action"]); 
    Assert.AreEqual("a", actionResult.RouteValues["controller"]); 
} 

public class TestModel 
{ 
    public UnregisteredController Controller { get; set; } 
    public Mock<ControllerContext> ControllerContext { get; set; } 
    public Mock<IQ_Member> QMember { get; set; } 

    public TestModel() 
    { 
     ControllerContext = new Mock<ControllerContext>(); 
     QMember = new Mock<IQ_Member>(); 
    } 

    public UnregisteredController ReturnController() 
    { 
     Controller = new UnregisteredController(QMember.Object); 
     Controller.ControllerContext = ControllerContext.Object; 
     return Controller; 
    } 
} 

回答

3

this SO post,你只能实现使用起订量的虚拟/抽象成员。

一般non-ASP.NET MVC的情况下,您可以

  1. 用嘲弄的工具,这将允许非虚,具体类成员的首要或

  2. 写下您的用静态/非虚拟成员的传递方法来创建自己的包装类,从这些包装类中提取接口,然后设计剩余的代码以依赖这些接口,然后可以轻松地对它们进行模拟和依赖注入。

我会建议#2#超过1上方,即使它会导致相当数量的工作,因为#2几乎肯定会导致代码更好地附着在Dependency Inversion principle

但在你的情况下,我认为有一个相当简单的解决方案。

在代码的行

_testModel.ControllerContext.SetupGet(p => p.HttpContext.Request.Url.Authority).Returns("www.localhost.com"); 
  • .HttpContext是抽象的,因此它可以被模拟
  • .Request是抽象的,因此它可以被模拟
  • .Url是虚拟因此它可以被模拟
  • .Authority是一个非虚拟的字符串属性,这是什么给你的问题

试试这个,因为.Url是,你可以嘲笑最深的部分:

_testModel.ControllerContext.SetupGet(p => p.HttpContext.Request.Url).Returns(new Uri("http://www.localhost.com"));