【问题标题】:How do i mock Url object in asp.net mvc我如何在 asp.net mvc 中模拟 Url 对象
【发布时间】:2017-03-12 18:09:35
【问题描述】:

我的一些控制器操作调用此方法GenerateActionLink

    private string GenerateActionLink(string actionName, string token, string username)
    {
        string validationLink = null;
        if (Request.Url != null)
        {
            var encodedToken = EncodedUrlParameter(token);
            var url = Url.Action(actionName, "Register", new {Token = encodedToken, Username = username}, Request.Url.Scheme);
            validationLink = url;
        }

        return validationLink;
    }

这是为了生成一个验证链接,该链接将通过电子邮件发送。它完美地工作。我遇到的问题是在测试调用该方法的控制器操作时。网址为空。

我如何模拟它并在我的单元测试中使用模拟?

我正在使用MoqNUnit

注意:我需要能够传入一个 actionName,这就是为什么我没有将 Request.Url 与我的参数值连接起来,因为 Request.Url 将始终具有请求来自的操作,通常不是我的操作想要在链接中,这就是我使用 Url.Action 生成操作链接的原因。

【问题讨论】:

  • 模拟UrlHelper并在安排测试时设置控制器的Url属性。模拟请求模拟控制器的 http 上下文并设置控制器上下文。

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


【解决方案1】:

在安排测试时模拟UrlHelper 并设置控制器的Url 属性。模拟请求模拟控制器的 http 上下文并设置控制器上下文。

这里演示的是基于上面提供的示例的示例控制器。

public class MyController : Controller {
    [HttpPost]
    public ActionResult MyAction() {
        var link = GenerateActionLink("MyTargetActionName", string.Empty, string.Empty);

        return View((object)link);
    }

    private string GenerateActionLink(string actionName, string token, string username) {
        string validationLink = null;
        if (Request.Url != null) {
            var encodedToken = EncodedUrlParameter(token);
            var url = Url.Action(actionName, "Register", new { Token = encodedToken, Username = username }, Request.Url.Scheme);
            validationLink = url;
        }

        return validationLink;
    }

    private string EncodedUrlParameter(string token) {
        return "Fake encoding";
    }

}

这是一个模拟所有必要框架依赖项的单元测试示例

[TestClass]
public class UrlHelperTest {
    [TestMethod]
    public void MockUrlHelper() {
        //Arrange
        var requestUrl = new Uri("http://myrequesturl");
        var request = Mock.Of<HttpRequestBase>();
        var requestMock = Mock.Get(request);
        requestMock.Setup(m => m.Url).Returns(requestUrl);

        var httpcontext = Mock.Of<HttpContextBase>();
        var httpcontextSetup = Mock.Get(httpcontext);
        httpcontextSetup.Setup(m => m.Request).Returns(request);


        var actionName = "MyTargetActionName";
        var expectedUrl = "http://myfakeactionurl.com";
        var mockUrlHelper = new Mock<UrlHelper>();
        mockUrlHelper
            .Setup(m => m.Action(actionName, "Register", It.IsAny<object>(), It.IsAny<string>()))
            .Returns(expectedUrl)
            .Verifiable();

        var sut = new MyController();
        sut.Url = mockUrlHelper.Object;
        sut.ControllerContext = new ControllerContext {
            Controller = sut,
            HttpContext = httpcontext,
        };

        //Act
        var result = sut.MyAction();

        //Assert
        mockUrlHelper.Verify();
    }
}

【讨论】:

  • 这解决了我的问题。谢谢。
【解决方案2】:

所以这是我目前的解决方案,我最终手动构建了链接。如果有更好的解决方案,请告诉我。

    private string GenerateActionLink(string actionName, string token, string username)
    {
        string validationLink = null;
        if (Request.Url != null)
        {
            var encodedToken = EncodedUrlParameter(token);
            var encodedEmail = EncodedUrlParameter(username);
            var concatenatedUrl =
                $"{Request.Url.Scheme}://{Request.Url.Host}/Register/{actionName}?Token={encodedToken}&Username={encodedEmail}"; 
            validationLink = concatenatedUrl;
        }

        return validationLink;
    }

这样我仍然可以传递actionName。如果我使用 Request.Url,这将始终有一个通常不是我想要使用的操作,如我的问题所述。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 2013-10-01
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    • 2020-07-29
    相关资源
    最近更新 更多