【问题标题】:How to Unit Test HtmlHelper with Moq?如何使用 Moq 对 HtmlHelper 进行单元测试?
【发布时间】:2011-01-30 13:20:10
【问题描述】:

有人可以告诉我你将如何使用 Moq 创建一个模拟 HTML 助手吗?

这个article 有一个链接到一篇声称描述这个的文章,但是点击这个链接只会返回一个 ASP.NET 运行时错误

[编辑] 我问了一个与同一主题相关的更具体的问题here,但没有得到任何回应。我觉得它太具体了,所以我想我可以对一个更一般的问题得到一个更一般的答案,然后修改它以满足我的要求。

谢谢

【问题讨论】:

  • 你能提供一些正在测试的代码吗?
  • @Samuel,相关代码在我在编辑中链接到的问题中。
  • 我实际上不知道一个好的答案(不记得 c# 的细节),但我赞成它以试图引起一些关注 =)

标签: asp.net-mvc unit-testing nunit moq html-helper


【解决方案1】:

Here 的另一篇文章向您展示了如何实现相同的目标:

public static HtmlHelper CreateHtmlHelper(ViewDataDictionary vd)
{
  var mockViewContext = new Mock<ViewContext>(
    new ControllerContext(
      new Mock<HttpContextBase>().Object,
      new RouteData(),
      new Mock<ControllerBase>().Object),
    new Mock<IView>().Object,
    vd,
    new TempDataDictionary());

  var mockViewDataContainer = new Mock<IViewDataContainer>();
  mockViewDataContainer.Setup(v => v.ViewData).Returns(vd);

  return new HtmlHelper(mockViewContext.Object, mockViewDataContainer.Object);
}

【讨论】:

  • 这应该是公认的答案。该对象实际上是在这里模拟的。
  • 我对 MVC5 进行了更改。等待同行评审。
【解决方案2】:

你可以这样做:

HtmlHelper helper = null;
helper.YourHelperMethod();

无需嘲笑任何东西。对我来说效果很好。

【讨论】:

  • 这只有在你编写了一个根本不使用辅助方法的辅助方法时才有效,显然。如果您尝试访问ViewContextRouteCollection 或其他任何地址,这对您没有帮助。
  • 这不应该是公认的答案。它只回答一个场景,而不是您必须使用 Html Helper 的情况。就像@MattEnright 说的那样,如果您需要使用测试Html Helper 来生成Action Link,它不会帮助您。
  • 这显然是一个嘲讽的答案-)
  • 这个答案完全忽略了在您正在测试的方法中尝试实际使用 HtmlHelper 的现实。听起来像是生成 NullReferenceException 的好方法。
【解决方案3】:

在 MVC5 中,ViewContextTextWriter 提供了一个额外的构造函数参数,因此 Thomas 的代码不再有效。我添加了一个内存中的 TextWriter 来解决这个问题:

public static HtmlHelper CreateHtmlHelper(ViewDataDictionary vd)
{
    Mock<ViewContext> mockViewContext = new Mock<ViewContext>(
        new ControllerContext(
            new Mock<HttpContextBase>().Object,
            new RouteData(),
            new Mock<ControllerBase>().Object
        ),
        new Mock<IView>().Object,
        vd,
        new TempDataDictionary(),
        new StreamWriter(new MemoryStream())
    );

    Mock<IViewDataContainer> mockDataContainer = new Mock<IViewDataContainer>();
    mockDataContainer.Setup(c => c.ViewData).Returns(vd);

    return new HtmlHelper(mockViewContext.Object, mockDataContainer.Object);
}

【讨论】:

  • 为了使用 ViewBag,我将方法签名更改为 public static HtmlHelper CreateHtmlHelper(ViewDataDictionary vd, object clientData) 并将返回行更改为 var htmlHelper = new HtmlHelper(mockViewContext.Object, mockViewDataContainer.Object); htmlHelper.ViewBag.Client = clientData; return htmlHelper;
  • 这是迄今为止最好的答案,但如果您有一个使用 htmlHelper 的 html 助手,它将无法工作。例如,如果您使用 Html.action(...) 这将生成一个空答案。
  • 这里ViewContext有什么用。似乎从未使用过vc
  • @Blaise 你说得对,好像没用过。感谢您的提醒
  • 您还需要将 CallBase 设置为 true 以确保 ViewContext 属性正常工作:var mockViewContext = new Mock&lt;ViewContext&gt;( new ControllerContext( new Mock&lt;HttpContextBase&gt;().Object, new RouteData(), new Mock&lt;ControllerBase&gt;().Object), Mock.Of&lt;IView&gt;(), vd, new TempDataDictionary(), new StringWriter()) { CallBase = true };
【解决方案4】:

要测试 BeginForm 等可访问 ViewContext.Writer 的一次性助手,您可以使用以下方法:

public static HtmlHelper CreateHtmlHelper(ViewDataDictionary vd, Stream stream = null)
{
    TextWriter textWriter = new StreamWriter(stream ?? new MemoryStream());
    Mock<ViewContext> mockViewContext = new Mock<ViewContext>(
        new ControllerContext(
            new Mock<HttpContextBase>().Object,
            new RouteData(),
            new Mock<ControllerBase>().Object
        ),
        new Mock<IView>().Object,
        vd,
        new TempDataDictionary(),
        textWriter
    );
    mockViewContext.Setup(vc => vc.Writer).Returns(textWriter);

    Mock<IViewDataContainer> mockDataContainer = new Mock<IViewDataContainer>();
    mockDataContainer.Setup(c => c.ViewData).Returns(vd);

    return new HtmlHelper(mockViewContext.Object, mockDataContainer.Object);
}

【讨论】:

  • 肯定少了点什么。我有一个System.NullReferenceException。 “你调用的对象是空的”。有什么想法吗?
  • 您可能需要确保在模拟对象上将CallBase 设置为true,以便正确设置属性。你也不应该需要mockViewContext.Setup(vc =&gt; vc.Writer).Returns(textWriter);
  • 那行mockDataContainer.Setup(c =&gt; c.ViewData).Returns(vd);应该是mockDataContainer.SetupGet(c =&gt; c.ViewData).Returns(vd);
猜你喜欢
  • 1970-01-01
  • 2011-12-24
  • 2012-06-01
  • 2014-12-30
  • 2021-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多