单元测试Url.IsLocalUrl(returnUrl.ToString()),我怎样才能让它在单元测试中返回false?

时间:2012-02-27 10:09:03

标签: asp.net-mvc-3 url local returnurl

从MVC3应用程序中的帐户控制器中的标准LogOn方法,我该如何测试

Url.IsLocalUrl(returnUrl.ToString()) 

网址不在本地的代码行?换句话说,在进行单元测试时,我必须将这些代码添加到这行代码中,以使其返回false?

我使用了以下思路,这将作为false(非本地)返回:

Uri uri = new Uri(@"http://www.google.com/blahblah.html");

但它只是在单元测试中抛出了一个null异常

编辑:我应该补充一点,LogOn方法现在看起来像这样:

public ActionResult LogOn(LogOnModel model, System.Uri returnUrl)

if (ModelState.IsValid) {

            bool loggedOn = LogOn(model);

            if (loggedOn) {
                if (Url.IsLocalUrl(returnUrl.ToString())) {
                    return Redirect(returnUrl.ToString());
                }
                else {
                    return RedirectToAction("Index", "Home");
                }
            }
            else {
                ModelState.AddModelError("", "The user name or password provided is incorrect.");
            }
        }

        // If we got this far, something failed, redisplay form
        return View(viewModel);
    }

某些样式警察/代码分析错误强制从字符串参数更改为System.uri参数,但它与标准原件非常相似。

只是为了澄清一下,在单元测试中 - 我想测试并断言点击Else行重定向到Home/Index的结果,所以我需要将一些内容传递给(System.Uri)returnUrl 1}}会使它在Url.IsLocalUrl上返回false而不会抛出异常

进一步编辑:

我正在使用MvcContrib testhelper,它非常善于嘲笑很多httpcontext和web的东西:

Builder = new TestControllerBuilder();
UserController = new UserController();
    Builder.InitializeController(UserController);

2 个答案:

答案 0 :(得分:17)

您需要模拟HttpContext以及您要进行单元测试的控制器上的UrlHelper实例。以下是使用Moq时单位测试的外观示例:

[TestMethod]
public void LogOn_Should_Redirect_To_Home_If_Authentication_Succeeds_But_Not_Local_ReturnUrl_Is_Provided()
{
    // arrange
    var sut = new AccountController();
    var model = new LogOnModel();
    var returnUrl = new Uri("http://www.google.com");
    var httpContext = new Mock<HttpContextBase>();
    var request = new Mock<HttpRequestBase>();
    httpContext.Setup(x => x.Request).Returns(request.Object);
    request.Setup(x => x.Url).Returns(new Uri("http://localhost:123"));
    var requestContext = new RequestContext(httpContext.Object, new RouteData());
    sut.Url = new UrlHelper(requestContext);

    // act
    var actual = sut.LogOn(model, returnUrl);

    // assert
    Assert.IsInstanceOfType(actual, typeof(RedirectToRouteResult));
    var result = (RedirectToRouteResult)actual;
    Assert.AreEqual("Home", result.RouteValues["controller"]);
    Assert.AreEqual("Index", result.RouteValues["action"]);
}

备注:由于您实际上已经显示了要调用凭据的LogOn实现,因此您可能需要调整单元测试以确保此方法在给定模型的第一个位置返回true输入if (loggedOn)条款。


更新:

您似乎正在使用MvcContrib.TestHelper为您执行所有HttpContext模拟设置。因此,您需要做的就是模拟单元测试的相关部分:

[TestMethod]
public void LogOn_Should_Redirect_To_Home_If_Authentication_Succeeds_But_Not_Local_ReturnUrl_Is_Provided()
{
    // arrange
    var sut = new AccountController();
    new TestControllerBuilder().InitializeController(sut);
    var model = new LogOnModel();
    var returnUrl = new Uri("http://www.google.com");
    sut.HttpContext.Request.Expect(x => x.Url).Return(new Uri("http://localhost:123"));

    // act
    var actual = sut.LogOn(model, returnUrl);

    // assert
    actual
        .AssertActionRedirect()
        .ToController("Home")
        .ToAction("Index");
}

通常,单元测试的前两行可以移动到全局[SetUp]方法,以避免在此控制器的每个单元测试中重复它们,以便现在您的测试变得更加清洁:

[TestMethod]
public void LogOn_Should_Redirect_To_Home_If_Authentication_Succeeds_But_Not_Local_ReturnUrl_Is_Provided()
{
    // arrange
    var model = new LogOnModel();
    var returnUrl = new Uri("http://www.google.com");
    _sut.HttpContext.Request.Expect(x => x.Url).Return(new Uri("http://localhost:123"));

    // act
    var actual = _sut.LogOn(model, returnUrl);

    // assert
    actual
        .AssertActionRedirect()
        .ToController("Home")
        .ToAction("Index");
}

答案 1 :(得分:0)

我降落在这里搜索控制器中的空引用和当前答案的日期是否过时。我使用moq可以很好地做到这一点:

var mockUrlHelper = new Mock<IUrlHelper>();
mockUrlHelper.Setup(m => m.IsLocalUrl(It.IsAny<string>())).Returns(false);

var controller = new MyController();
controller.Url = mockUrlHelper.Object;