asp.net-mvc - Moq - 如何模拟 HttpContext.Request.Url.Authority 对象等非虚拟成员?

标签 asp.net-mvc tdd moq

我似乎无法使用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;
    }
}

最佳答案

根据this SO post ,您只能使用 Moq 来实现虚拟/抽象成员。

在一般的非 ASP.NET MVC 情况下,您可以

  1. 使用允许覆盖非虚拟、具体类成员的模拟工具或

  2. 使用静态/非虚拟成员的传递方法编写自己的包装类,从这些包装类中提取接口(interface),然后设计其余的代码以依赖于这些接口(interface),这样就可以轻松地被 mock 并注入(inject)依赖。

我会推荐#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"));

关于asp.net-mvc - Moq - 如何模拟 HttpContext.Request.Url.Authority 对象等非虚拟成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14461874/

相关文章:

unit-testing - 您是否遇到过 TDD 增加开发时间的情况?

java - 使用jmockit测试main方法

c# - 如何模拟 Entity Framework 6 异步方法?

c# - Moq:Lambda 表达式作为参数并在返回中评估它们

asp.net-mvc - ASP.NET MVC 3 (Razor) 应用程序中的多种语言

c# - 如何在 Asp.net MVC 中使用文件类型将文件内容保存在数据库表中

asp.net-mvc - MVC HttpGet 属性

c# - 如何在 ASP.NET MVC 中获取错误状态代码

使用 spy 进行 meteor 测试

mocking - 为什么要麻烦模拟存储库?