【问题标题】:ASP.NET 5 - MVC 6 - Unit Test a Controller that uses Url.ActionASP.NET 5 - MVC 6 - 对使用 Url.Action 的控制器进行单元测试
【发布时间】:2016-02-09 05:50:29
【问题描述】:

我有一个带有以下代码行的 MVC6 控制器:

string link = Url.Action("Profile", "Account");

当我对该控制器进行单元测试时,该行失败并出现错误:

Value cannot be null.
Parameter name: helper

我真的不想模拟 Url.Action 响应,而且我认为我不能,因为它是一种扩展方法(静态方法)。我希望它像在 Web 环境中一样运行和返回。

在我的单元测试中实例化控制器时,我需要做什么才能使上面的行按预期执行?

我发现我可以在我的单元测试中做这样的事情:

controller.Url = new UrlHelper(new ActionContextAccessor(), new DefaultActionSelector(...));

但我不知道设置 ActionContextAccessor 和/或 DefaultActionSelector 需要什么(这需要更多类型,我不确定从哪里获取或如何实例化)。

有人已经这样做了吗?

谢谢, 凯文

【问题讨论】:

    标签: c# asp.net-mvc unit-testing


    【解决方案1】:

    当我遇到困难时,我的妻子总是告诉我“走开”。而且她几乎总是对的。

    在意识到上面的解决方案行不通后(因为它是 MVC5),我又看了看,意识到 controller.Url 只是 IUrlHelper 的一个实例。我对此进行了嘲笑,poof 测试开始起作用了。这是我正在做的事情的要点。这使得测试能够执行。我确信我可以在模拟中添加更多内容,以实际验证它是否按预期运行。

            Mock<IUrlHelper> urlHelperMock = new Mock<IUrlHelper>();
            var controller = new BooksController();
            controller.Url = urlHelperMock.Object;
    

    是的,就是这么简单,哈哈。

    谢谢, 凯文

    【讨论】:

      【解决方案2】:

      给定:

      namespace SampleWebApplication.Controllers
      {
          public class HomeController : Controller
          {
              public ActionResult Index()
              {
                  string link = Url.Action("Profile", "Account");
                  return View();
              }
          }
      }
      

      这个测试似乎运行通过了:

      using System;
      using System.Collections.Specialized;
      using System.Web;
      using System.Web.Mvc;
      using System.Web.Routing;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      using Moq;
      using SampleWebApplication.Controllers;
      
      namespace SampleUnitTestProject
      {
          [TestClass]
          public class HomeTests
          {
              private Mock<HttpRequestBase> RequestMock;
              private Mock<HttpResponseBase> ResponseMock;
              private Mock<HttpContextBase> ContextMock;
      
              [TestInitialize]
              public virtual void Setup()
              {
                  this.RequestMock = new Mock<HttpRequestBase>();
                  this.ResponseMock = new Mock<HttpResponseBase>();
                  this.RequestMock.Setup(m => m.QueryString).Returns(new NameValueCollection());
                  this.RequestMock.Setup(m => m.Url).Returns(new Uri("http://www.somedomain.com"));
                  this.ContextMock = new Mock<HttpContextBase>();
      
                  this.ContextMock.Setup(m => m.Request).Returns(this.RequestMock.Object);
                  this.ContextMock.Setup(m => m.Response).Returns(this.ResponseMock.Object);
              }
      
              [TestMethod]
              public void Test_Index()
              {
                  // Arrange
      
                  using (var controller = new HomeController())
                  {
                      this.RequestMock.Setup(c => c.ApplicationPath).Returns("/tmp/testpath");
                      this.ResponseMock.Setup(c => c.ApplyAppPathModifier(It.IsAny<string>())).Returns("/mynewVirtualPath/");
                      var requestContext = new RequestContext(this.ContextMock.Object, new RouteData());
                      controller.Url = new UrlHelper(requestContext, new RouteCollection());
      
                      // Act
                      var result = controller.Index();
      
                      // Assert
                  }
              }
          }
      }
      

      【讨论】:

      • 这看起来像 MVC5 (System.Web.*)。我在 MVC6 (Microsoft.AspNet.*) 中。
      猜你喜欢
      • 1970-01-01
      • 2016-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-21
      • 2014-02-08
      相关资源
      最近更新 更多