【发布时间】:2015-12-18 11:38:47
【问题描述】:
我们有一些控制器操作可以将面包屑节点的标题更改为用户正在查看的项目的值,例如
[MvcSiteMapNode(Title = "{0}", ParentKey = "Maintenance-Settings-Index", Key = "Maintenance-Settings-Details", PreservedRouteParameters = "id", Attributes = "{\"visibility\":\"SiteMapPathHelper,!*\"}")]
public async Task<ActionResult> Details(int id)
{
var model = await GetSetting(id);
var node = SiteMaps.Current.CurrentNode;
if (node != null)
{
node.Title = string.Format("{0}", model.Name);
}
return View(model);
}
这在正常查看网站时可以正常工作,并且可以按照我们想要的方式运行..
但是...当尝试使用 Moq 和 FluentMVCTesting 对控制器操作进行单元测试时,我们遇到了错误。
从http://www.shiningtreasures.com/post/2013/08/14/mvcsitemapprovider-4-unit-testing-with-the-sitemaps-static-methods 我们添加了SiteMaps.Loader = new Mock<ISiteMapLoader>().Object; 例如
创建控制器上下文
private static ControllerContext FakeControllerContext(RouteData routeData)
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new MockHttpSession();
var server = new Mock<HttpServerUtilityBase>();
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session);
context.Setup(ctx => ctx.Server).Returns(server.Object);
var controllerContext = new ControllerContext(context.Object, routeData ?? new RouteData(), new Mock<ControllerBase>().Object);
return controllerContext;
}
为每个测试初始化控制器
[TestInitialize]
public void Initialize()
{
var routeData = new RouteData();
_controller = new DepartmentSettingsController
{
ControllerContext = FakeControllerContext(routeData)
};
}
然后是测试本身
[TestMethod]
public void Details()
{
SiteMaps.Loader = new Mock<ISiteMapLoader>().Object;
_controller.WithCallTo(c => c.Details(_model.Id)).ShouldRenderDefaultView()
.WithModel<SettingViewModel>(m => m.Name == _model.Name);
}
我们得到以下错误 System.NullReferenceException: Object reference not set to an instance of an object. 指的是var node = SiteMaps.Current.CurrentNode;
然后我们添加另一个测试
[TestMethod]
public void Edit()
{
SiteMaps.Loader = new Mock<ISiteMapLoader>().Object;
_controller.WithCallTo(c => c.Edit(_model.Id)).ShouldRenderDefaultView()
.WithModel<SettingViewModel>(m => m.Name == _model.Name);
}
并得到MvcSiteMapProvider.MvcSiteMapException:站点地图加载器只能在Global.asax的Application_Start事件中设置,不得再次设置。如果您使用的是外部依赖注入容器,请将 web.config 文件的 AppSettings 部分中的“MvcSiteMapProvider_UseExternalDIContainer”设置为“true”。 在 MvcSiteMapProvider.SiteMaps.set_Loader(ISiteMapLoader 值)
然后将SiteMaps.Loader = new Mock<ISiteMapLoader>().Object; 移动到测试初始化例如
[TestInitialize]
public void Initialize()
{
var routeData = new RouteData();
_controller = new DepartmentSettingsController
{
ControllerContext = FakeControllerContext(routeData)
};
SiteMaps.Loader = new Mock<ISiteMapLoader>().Object;
}
我们得到同样的错误 MvcSiteMapProvider.MvcSiteMapException: 站点地图加载器只能在 Global.asax 的 Application_Start 事件中设置,不得再次设置。如果您使用的是外部依赖注入容器,请将 web.config 文件的 AppSettings 部分中的“MvcSiteMapProvider_UseExternalDIContainer”设置为“true”。 在 MvcSiteMapProvider.SiteMaps.set_Loader(ISiteMapLoader 值)
问题 - 当您测试多个操作时,SiteMaps.Loader = new Mock<ISiteMapLoader>().Object; 在单元测试中的最佳位置在哪里
问题 - 使用静态 var node = SiteMaps.Current.CurrentNode; 是进入控制器的最佳方式,还是有更好的方式(我们使用 Unity)
感谢您的帮助
【问题讨论】:
标签: unit-testing moq mvcsitemapprovider asp.net-mvc-sitemap