2012-02-27 158 views
4

从在MVC3应用帐户控制标准的登录方法,我怎么能测试单元测试Url.IsLocalUrl(returnUrl.ToString()),我怎么能得到它在单元测试中返回false?

Url.IsLocalUrl(returnUrl.ToString()) 

行代码,其中的网址是不是本地的?换句话说,当单元测试时,我需要将哪些网址送入此代码行,才能让它返回false?

我用下面想这将返回假(非本地):

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

,但它只是扔在单位空异常测试

编辑:我要补充的是,登录方法现在看起来是这样的:

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参数改变,但它是非常相似的TH一些风格COP /代码分析错误e标准原件。

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

进一步编辑:

我使用MvcContrib testhelper,这是在嘲讽了很多的HttpContext和网络的东西还不错:

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

回答

15

您需要模拟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)子句。


UPDATE:

看来你正在使用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"); 
} 
+0

对不起达林我应该还补充说我使用MvcContrib TestHelper,见上编辑。相当新,但我认为它涵盖了很多嘲讽问题..? – DevDave 2012-02-27 10:50:55

+0

@泰勒,的确,你应该在你的问题中提到这一点。我已经更新了我的答案,以提供如何使用MvcContrib.TestHelper来实现这一目标的示例。 – 2012-02-27 10:56:49

+0

@Tyler,'new Uri(“google.co。uk“)'是一个无效的uri,它会抛出'UriFormatException'。你需要指定协议。 – 2012-02-27 11:47:07