我有一个带有以下代码行的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需要什么(需要更多类型,我不确定从何处获取或如何实例化)。
有没有人这样做过?
谢谢, 凯文
答案 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
}
}
}
}