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

Dev*_*ave 6 url local returnurl asp.net-mvc-3

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

Url.IsLocalUrl(returnUrl.ToString()) 
Run Code Online (Sandbox Code Playgroud)

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

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

Uri uri = new Uri(@"http://www.google.com/blahblah.html");
Run Code Online (Sandbox Code Playgroud)

但它只是在单元测试中抛出了一个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);
    }
Run Code Online (Sandbox Code Playgroud)

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

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

进一步编辑:

我正在使用MvcContrib testhelper,它非常擅长模拟很多httpcontext和web的东西:

Builder = new TestControllerBuilder();
UserController = new UserController();
    Builder.InitializeController(UserController);
Run Code Online (Sandbox Code Playgroud)

Dar*_*rov 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"]);
}
Run Code Online (Sandbox Code Playgroud)

备注:由于您实际上已经显示了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");
}
Run Code Online (Sandbox Code Playgroud)

通常,单元测试的前两行可以移动到全局[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");
}
Run Code Online (Sandbox Code Playgroud)