ASP.NET 5 - MVC 6 - 单元测试使用Url.Action的控制器

时间:2016-01-15 17:35:44

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

我有一个带有以下代码行的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需要什么(需要更多类型,我不确定从何处获取或如何实例化)。

有没有人这样做过?

谢谢, 凯文

2 个答案:

答案 0 :(得分:5)

当我被困住时,我的妻子总是告诉我只是“离开”一个问题。她几乎总是对的。

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

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

是的,这很容易LOL。

谢谢, 凯文

答案 1 :(得分:0)

假设:

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
            }
        }
    }
}