如何对System.Web.Mvc.Controller的Initialize()方法进行单元测试?
我想对 Controller 对象的 Initialize 方法进行单元测试。 Initialize() 方法基本上从请求对象的 cookies 集合中提取玩家的 ID,并从数据库中检索当前玩家对象。然后播放器对象存储在控制器对象的 CurrentPlayer 属性中。我有以下单元测试代码。该测试基本上是为控制器的 Index () 方法编写的:
[Test]
public void Index_ReturnsJsonResult ()
{
var _gameRepositoryMock = GameRepositoryCreator.Create (5);
var _formsAuthenticationMock = new Mock<IFormsAuthentication> ();
var _chooseOpponentController = new ChooseOpponentController (_gameRepositoryMock.Object, _formsAuthenticationMock.Object);
var cookie = new HttpCookie (cookieName);
cookie.Value = player.PlayerID + "_encrypted";
var cookies = new HttpCookieCollection ();
cookies.Add (cookie);
var httpRequestMock = new Mock<HttpRequestBase> ();
httpRequestMock.Setup (x => x.Cookies).Returns (cookies);
httpRequestMock.Setup (x => x.IsAuthenticated).Returns (true);
var httpContextMock = new Mock<HttpContextBase> ();
httpContextMock.Setup (x => x.Request).Returns (httpRequestMock.Object);
var rd = new RouteData ();
rd.Values.Add ("action", "Index");
rd.Values.Add ("controller", "ChooseOpponent");
var requestContext = new RequestContext (httpContextMock.Object, rd);
_formsAuthenticationMock.Setup (x => x.Decrypt (cookie.Value)).Returns (player.PlayerID + "");
(_chooseOpponentController as IController).Execute (requestContext);
Assert.IsNotNull (_chooseOpponentController.CurrentPlayer);
... // test other things for the Index () method
}
Index () 方法声明为:
[Authorize, SavePlayerStatus(Order=2), CommitChanges(Order=1)]
public ActionResult Index ()
{ ... }
Initialize () 方法执行成功,但之后出现异常,并显示以下消息:“对象引用未设置为对象的实例。”,并且堆栈跟踪如下所示:
at System.Web.Compilation.BuildManager.GetCacheKeyFromVirtualPath(VirtualPath virtualPath, Boolean& keyFromVPP)
at System.Web.Compilation.BuildManager.GetVPathBuildResultFromCacheInternal(VirtualPath virtualPath, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean throwIfNotFound)
at System.Web.Mvc.BuildManagerWrapper.System.Web.Mvc.IBuildManager.FileExists(String virtualPath)
at System.Web.Mvc.BuildManagerViewEngine.FileExists(ControllerContext controllerContext, String virtualPath)
at System.Web.Mvc.VirtualPathProviderViewEngine.GetPathFromGeneralName(ControllerContext controllerContext, List`1 locations, String name, String controllerName, String areaName, String cacheKey, String[]& searchedLocations)
at System.Web.Mvc.VirtualPathProviderViewEngine.GetPath(ControllerContext controllerContext, String[] locations, String[] areaLocations, String locationsPropertyName, String name, String controllerName, String cacheKeyPrefix, Boolean useCache, String[]& searchedLocations)
at System.Web.Mvc.VirtualPathProviderViewEngine.FindView(ControllerContext controllerContext, String viewName, String masterName, Boolean useCache)
at System.Web.Mvc.ViewEngineCollection.<>c__DisplayClassc.<FindView>b__b(IViewEngine e)
at System.Web.Mvc.ViewEngineCollection.Find(Func`2 lookup, Boolean trackSearchedPaths)
at System.Web.Mvc.ViewEngineCollection.FindView(ControllerContext controllerContext, String viewName, String masterName)
at System.Web.Mvc.ViewResult.FindView(ControllerContext context)
at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1c.<>c__DisplayClass1e.<InvokeActionResultWithFilters>b__1b()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
感谢任何帮助。
I would like to unit test the Initialize method of a Controller object. The Initialize () method basically extracts the player's ID from the cookies collection of the request object and retrieves the current player object from the database. Then the player object is stored in the controller object's CurrentPlayer property. I have the following code for the unit test. This test is basically written for the Index () method of the controller:
[Test]
public void Index_ReturnsJsonResult ()
{
var _gameRepositoryMock = GameRepositoryCreator.Create (5);
var _formsAuthenticationMock = new Mock<IFormsAuthentication> ();
var _chooseOpponentController = new ChooseOpponentController (_gameRepositoryMock.Object, _formsAuthenticationMock.Object);
var cookie = new HttpCookie (cookieName);
cookie.Value = player.PlayerID + "_encrypted";
var cookies = new HttpCookieCollection ();
cookies.Add (cookie);
var httpRequestMock = new Mock<HttpRequestBase> ();
httpRequestMock.Setup (x => x.Cookies).Returns (cookies);
httpRequestMock.Setup (x => x.IsAuthenticated).Returns (true);
var httpContextMock = new Mock<HttpContextBase> ();
httpContextMock.Setup (x => x.Request).Returns (httpRequestMock.Object);
var rd = new RouteData ();
rd.Values.Add ("action", "Index");
rd.Values.Add ("controller", "ChooseOpponent");
var requestContext = new RequestContext (httpContextMock.Object, rd);
_formsAuthenticationMock.Setup (x => x.Decrypt (cookie.Value)).Returns (player.PlayerID + "");
(_chooseOpponentController as IController).Execute (requestContext);
Assert.IsNotNull (_chooseOpponentController.CurrentPlayer);
... // test other things for the Index () method
}
The Index () method is declared as:
[Authorize, SavePlayerStatus(Order=2), CommitChanges(Order=1)]
public ActionResult Index ()
{ ... }
The Initialize () method is executed successfully but after that I get an exception with the following message: "Object reference not set to an instance of an object.", and the stack trace looks like this:
at System.Web.Compilation.BuildManager.GetCacheKeyFromVirtualPath(VirtualPath virtualPath, Boolean& keyFromVPP)
at System.Web.Compilation.BuildManager.GetVPathBuildResultFromCacheInternal(VirtualPath virtualPath, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean throwIfNotFound)
at System.Web.Mvc.BuildManagerWrapper.System.Web.Mvc.IBuildManager.FileExists(String virtualPath)
at System.Web.Mvc.BuildManagerViewEngine.FileExists(ControllerContext controllerContext, String virtualPath)
at System.Web.Mvc.VirtualPathProviderViewEngine.GetPathFromGeneralName(ControllerContext controllerContext, List`1 locations, String name, String controllerName, String areaName, String cacheKey, String[]& searchedLocations)
at System.Web.Mvc.VirtualPathProviderViewEngine.GetPath(ControllerContext controllerContext, String[] locations, String[] areaLocations, String locationsPropertyName, String name, String controllerName, String cacheKeyPrefix, Boolean useCache, String[]& searchedLocations)
at System.Web.Mvc.VirtualPathProviderViewEngine.FindView(ControllerContext controllerContext, String viewName, String masterName, Boolean useCache)
at System.Web.Mvc.ViewEngineCollection.<>c__DisplayClassc.<FindView>b__b(IViewEngine e)
at System.Web.Mvc.ViewEngineCollection.Find(Func`2 lookup, Boolean trackSearchedPaths)
at System.Web.Mvc.ViewEngineCollection.FindView(ControllerContext controllerContext, String viewName, String masterName)
at System.Web.Mvc.ViewResult.FindView(ControllerContext context)
at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1c.<>c__DisplayClass1e.<InvokeActionResultWithFilters>b__1b()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
Any help is appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
通过调用
Execute
,您实际上是在调用整个 MVC 管道。这包括尝试访问磁盘并查找视图文件的视图查找逻辑。失败的部分是 ASP.NET 编译系统未正确初始化。对于单元测试来说,你执行的太多了。我会编写 2 个测试:一个用于验证 Index 方法是否执行正确的操作,另一个用于验证 Initialize 方法是否执行正确的操作。其他一切(Initialize 在操作方法之前调用的事实等)都是 MVC 管道,您无需担心。
By calling
Execute
you are essentially calling the entire MVC pipeline. This includes the view lookup logic that tries to go to disk and find your view files. The part that's failing is the ASP.NET compilation system that is not initialized properly.For a unit test, you are executing too much. I would write 2 tests: one that verifies that the Index method does the right thing, and one that verifies that the Initialize method does the right thing. Everything else (the fact that Initialize gets called before the action method, etc) is MVC plumbing that you should not need to worry about.