简体   繁体   中英

ASP.NET 5 - MVC 6 - Unit Test a Controller that uses Url.Action

I have an MVC6 controller with the following line of code:

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

When I unit test this controller, that line fails with an error:

Value cannot be null.
Parameter name: helper

I don't really want to mock the Url.Action response plus I don't think I can because it's an extension method (static method). I want it to run and return like it would in a web environment.

What do I need to do when instantiating the controller in my unit test so that I the line above will execute as expected?

I see that I can do something like this in my unit test:

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

But I can't figure out what is needed to setup the ActionContextAccessor and/or the DefaultActionSelector (which requires more types that I'm not sure where to obtain or how to instantiate).

Has anyone already done this?

Thanks, Kevin

My wife always tells me to just "walk away" from a problem when I'm stuck. And she's almost always right.

After realizing the solution above wasn't going to work (because it's MVC5), I took another look and realized that controller.Url is just an instance of IUrlHelper. I mocked that and poof the tests started to work. Here's the gist of what I'm doing. This made the test able to execute. I'm sure I can add some more to the mocking to actually verify it's functioning as expected.

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

Yeah, it was that easy LOL.

Thanks, Kevin

Given:

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

This test seems to run through OK:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM