2011-05-17 96 views
5

我正在尝试创建集成测试以确保我的视图中没有任何运行时错误。因此,我需要创建一个测试,检查ViewResult.ExecuteResult()是否正常工作,但似乎我遇到了麻烦。我怎样才能正确地模拟我的controllercontext测试ViewResult.ExecuteResult()?

我发现this site这给了我一个起点,我有以下代码:

[TestMethod] 
    public void RegisterResultExecutes() 
    { 
     //arrange 
     RequestContext requestContext = new RequestContext(new MockHttpContext(), new RouteData()); 
     AccountController controller = new AccountController 
     { 
      FormsService = new MockFormsAuthenticationService(), 
      MembershipService = new MockMembershipService(), 
      Url = new UrlHelper(requestContext) 
     }; 

     var result = controller.Register(); 
     var sb = new StringBuilder(); 
     Mock<HttpResponseBase> response = new Mock<HttpResponseBase>(); 
     response.Setup(x => x.Write(It.IsAny<string>())).Callback<string>(y => 
     { 
      sb.Append(y); 
     }); 
     Mock<ControllerContext> controllerContext = new Mock<ControllerContext>(); 
     controllerContext.Setup(x => x.HttpContext.Response).Returns(response.Object); 

     //act 
     result.ExecuteResult(controllerContext.Object); 
    } 

的问题是,当result.ExecuteResult()叫我得到下面的异常

System.NullReferenceException: Object reference not set to an instance of an object. 

System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) 
MyApp.Tests.Controllers.AccountControllerTest.RegisterResultExecutes() in C:\Users\KallDrexx\Documents\Projects\MyApp\MyApp.Tests\Controllers\AccountControllerTests.cs: line 297 

不幸的是,该堆栈跟踪并不是非常有用,因为我不确定它试图访问的是空值。有没有人对我如何为ExecuteResult()创建测试有任何建议?

回答

4

基于堆栈跟踪,它是引发异常的ViewResultBase.ExecuteResult方法中的一些东西。使用反射器,这里是方法的定义:

public override void ExecuteResult(ControllerContext context) 
{ 
    if (context == null) 
    { 
     throw new ArgumentNullException("context"); 
    } 
    if (string.IsNullOrEmpty(this.ViewName)) 
    { 
     this.ViewName = context.RouteData.GetRequiredString("action"); 
    } 
    ViewEngineResult result = null; 
    if (this.View == null) 
    { 
     result = this.FindView(context); 
     this.View = result.View; 
    } 
    TextWriter output = context.HttpContext.Response.Output; 
    ViewContext viewContext = new ViewContext(context, this.View, this.ViewData, this.TempData, output); 
    this.View.Render(viewContext, output); 
    if (result != null) 
    { 
     result.ViewEngine.ReleaseView(context, this.View); 
    } 
} 

基于该代码,当代码试图从上下文访问RouteData属性的对象引用异常可能会被抛出(如果视图WASN的名称没有明确给出返回类型)。

通过访问HttpContext属性可能会抛出异常。我没有足够好地使用Moq知道它是否可以处理你没有告诉它如何模拟HttpContext属性的事实,但是你已经告诉它如何从HttpContext属性的类型中模拟Response属性,所以这是另一个我怀疑这个区域。

该方法中的上下文的所有其他用途将其传递给其他方法,如果这些问题存在,那么堆栈跟踪将显示该方法。

最简单的方法是查看我提到的两个问题中的哪一个是问题,我会写一个快速测试来从您的模拟中获取这些属性,并查看哪一个导致异常。

+0

啊哈,这折射出了大量的信息。它是'RouteData'导致的问题,但现在看来我需要找到'context.RouteData.GetRequiredString(“action”);'返回一些有用的东西,因为这就是我现在被卡住的地方 – KallDrexx 2011-05-17 03:19:43

+0

嗯在正确设置了'RouteData'之后,似乎我处于我能做的事情的极限,而这似乎是不可能的。对'FindView()'的调用在System.Web.Compilation.BuildManager中的堆栈跟踪中得到了一个'NullReferenceException'(字面上)层。GetCacheKeyFromVirtualPath()'。哦,很好:( – KallDrexx 2011-05-17 03:31:05

+0

我担心你会遇到这样的显示屏,你有什么具体的东西想要在你的视图中测试吗?如果你想确保你的lambda表达式是好的(如果你使用的话)你可以[编译你的意见](http://stackoverflow.com/questions/383192/compile-views-in-asp-net-mvc)。如果你想测试JavaScript,那么我会谷歌周围的JavaScript单元测试为我知道那里有框架,但我没有用过,或者你想单元测试其他东西吗? – 2011-05-17 12:13:16

1

我刚刚遇到同样的问题,并通过设置HttpContext.Current解决它。

尝试将以下内容添加到您的单元测试代码中:例如,

HttpContext.Current = new HttpContext(
    new HttpRequest("", "http://mock", ""), 
    new HttpResponse(new StringWriter())); 

有一两件事,我发现有用的调试这类问题,而不是使用反射器或ILSpy是打开.NET Framework的代码调试符号。这样,你可以附加到你的NUnit进程,并确切地看到哪些代码行抛出异常,因此你需要在测试中模拟。

肖恩·伯克写了一个优秀的博客文章中详细介绍了如何在这里设置此:http://blogs.msdn.com/b/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx

+0

哦整齐。感谢那 – KallDrexx 2012-03-20 12:38:39