2011-05-17 65 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