2011-12-08 65 views
0

我有一個MVC 3應用程序,我試圖單元測試。我從this page讀取了示例,演示瞭如何模擬控制器。這裏是我的測試代碼:控制器的單元測試錯誤結束

[TestMethod] 
    public void TestAddStudy() { 
     var controller = new AdminController(); 
     var httpContext = FakeHttpContext(); 
     var context = new ControllerContext(new RequestContext(httpContext, new RouteData()), controller); 
     controller.ControllerContext = context; 

     var request = Mock.Get(controller.Request); 
     request.Setup(r => r.Form).Returns(delegate() { 
      var nv = new FormCollection(); 
      nv.Add("Name", "Test Study"); 
      nv.Add("IsDefault", "selected"); 
      return nv; 
     }); 

     var result = controller.CreateStudy(request.Object.Form as FormCollection) as ActionResult; 

    } 

    public static HttpContextBase FakeHttpContext() { 
     var httpContext = new Mock<HttpContextBase>(); 
     var request = new Mock<HttpRequestBase>(); 
     var response = new Mock<HttpResponseBase>(); 
     var session = new Mock<HttpSessionStateBase>(); 
     var server = new Mock<HttpServerUtilityBase>(); 

     httpContext.Setup(ctx => ctx.Request).Returns(request.Object); 
     httpContext.SetupGet(ctx => ctx.Request.RequestType).Returns("POST"); 
     httpContext.Setup(ctx => ctx.Response).Returns(response.Object); 
     httpContext.Setup(ctx => ctx.Session).Returns(session.Object); 
     httpContext.Setup(ctx => ctx.Server).Returns(server.Object); 
     httpContext.SetupGet(ctx => ctx.User.Identity.Name).Returns("testClient"); 

     return httpContext.Object; 
    } 

這裏是控制器內部的代碼:

[HttpPost] 
    public ActionResult CreateStudy(FormCollection form) { 
     Study newStudy = new Study(); 
     TryUpdateModel(newStudy); 
     newStudy.CreatedBy = CurrentUser; 
     newStudy.CreatedOn = DateTime.Now; 
     studyRepository.Edit(newStudy, CurrentUser); 
     return RedirectToAction("EditStudy", new { id = 1 }); 
    } 

它無法與不設置到對象錯誤的實例的對象引用的TryUpdateModel聲明每次。我在做什麼錯了......或者更重要的是,我怎樣才能讓這個簡單的方法單元測試?

堆棧跟蹤: 在Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.CollectionReplacer.GetUnvalidatedCollections(HttpContext的上下文) 在Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.GetUnvalidatedCollections(HttpContext的背景下,函數功能 queryStringGetter) 在System.Web.Helpers.Validation.Unvalidated(HttpRequest請求) 在System.Web.Mvc.FormValueProviderFactory。 <。> b_ 0(ControllerContext cc) at System.Web.Mvc.FormValueProviderFactory.GetValueProvider(ControllerContext controllerContext) at System.Web.Mvc.ValueProviderFactoryCollection。 <>Ç _DisplayClassc.b__7(ValueProviderFactory工廠) 在System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext() at System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext() 在System.Collections.Generic.List 1..ctor(IEnumerable 1集合) 在System.Linq.Enumerable.ToList [TSource ]](IEnumerable`1源) 在System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(controllerContext controllerContext) 在System.Web.Mvc.ControllerBase.get_ValueProvider() 在System.Web.Mvc.Controller.TryUpdateModel [TModel的( TModel model) at C:\ Visual Studio Projects \ Controllers \ AdminController.cs中的Controllers.AdminController.CreateStudy(FormCollection窗體):第254行 at Tests.UnitTest1.TestAddStudy()in C :\ Visual Studio Projects \ Tests \ UnitTest1.cs:line 32

+1

請包括堆棧跟蹤。 – jrummell

+0

我只是想建議你使用MVC Contrib的TestHelper:http://mvccontrib.codeplex.com/wikipage?title=TestHelper它將成爲編寫測試的easyer。 – VinnyG

回答

0

此行實際上是返回一個對象還是爲空?

Study currentStudy = ctx.Studies.Where(p => p.StudyID == id).FirstOrDefault(); 

您可能需要調用TryUpdateModel(currentStudy)這樣之前檢查空:

Study currentStudy = ctx.Studies.Where(p => p.StudyID == id).FirstOrDefault(); 
if (currentStudy != null) { 
    TryUpdateModel(currentStudy); 
} 
+0

對不起,貼錯了方法。我實際上正在研究CreateStudy方法。 – Josh

0

看着堆棧跟蹤,它看起來像異常正在通話中拋出來TryUpdateModel(newStudy)。我只能想象new Study()返回的Study對象不符合TryUpdateModel()的要求,或者存在ASP.NET MVC爲使此方法正常工作而需要的一些依賴性,這在您的測試環境中是缺失的,但是存在於您的運行時上下文中(假設您在運行功能測試時控制器方法正在爲您工作)。

如果該方法在功能測試過程中起作用,則後面的解釋必須成立。在 Microsoft.Web.Infrastructure.DynamicValidationHelper

Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.CollectionReplacer.GetUnvalidatedCollections(HttpContext的背景下 ) - :再一次,看着堆棧跟蹤這裏。ValidationUtility.GetUnvalidatedCollections(HttpContext的 上下文,FUNC1 & formGetter,FUNC1 & queryStringGetter)在 System.Web.Helpers.Validation.Unvalidated(HttpRequest的請求)在

它看起來像HttpRequest被用於執行一些驗證。我猜你的模擬請求對象需要設置一些更多的方法/屬性返回值。特別是,我想它至少需要從FormQueryString屬性中返回NameValueCollection個實例,即使只是空的。假設MVC中的驗證代碼假設這些屬性從不返回空值是合理的。鑑於您尚未在模擬對象上設置這些屬性的返回值,這可以解釋爲什麼NullReferenceException在MVC代碼中被深入拋出。

嘗試添加這些行到你的模擬創建代碼: -

request.SetupGet(req => req.Form).Returns(new NameValueCollection()); 
request.SetupGet(req => req.QueryString).Returns(new NameValueCollection()); 

根據您的測試和/或控制的要求,你可能會發現,你將不得不增加一些值的至少一個NameValueCollection實例,以更準確地模擬真實請求的內容。

+0

添加了代碼,仍然無法對其進行單元測試。奇怪的是,該方法在使用應用程序時工作正常。我似乎無法讓它在單元測試中工作。 – Josh

+0

你是否得到相同的異常和堆棧跟蹤? –

+0

是的,還是一樣的錯誤。 – Josh