We have some controller actions that change the title of the breadcrumb node to be the value of the item the user is looking at e.g.
[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);
}
This works fine when viewing the site normally and behaves how we want it to..
However... When trying to unit test the controller actions using Moq and FluentMVCTesting we are getting errors.
From http://www.shiningtreasures.com/post/2013/08/14/mvcsitemapprovider-4-unit-testing-with-the-sitemaps-static-methods we added the SiteMaps.Loader = new Mock<ISiteMapLoader>().Object;
e.g.
Create the Controller Context
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;
}
Intialize the Controller for each test
[TestInitialize]
public void Initialize()
{
var routeData = new RouteData();
_controller = new DepartmentSettingsController
{
ControllerContext = FakeControllerContext(routeData)
};
}
Then the test itself
[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);
}
We get the following error System.NullReferenceException: Object reference not set to an instance of an object. which refers to var node = SiteMaps.Current.CurrentNode;
Then we add another Test
[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);
}
And get MvcSiteMapProvider.MvcSiteMapException: The sitemap loader may only be set in the Application_Start event of Global.asax and must not be set again. Set the 'MvcSiteMapProvider_UseExternalDIContainer' in the AppSettings section of the web.config file to 'true' if you are using an external dependency injection container. at MvcSiteMapProvider.SiteMaps.set_Loader(ISiteMapLoader value)
Then moving SiteMaps.Loader = new Mock<ISiteMapLoader>().Object;
into the test intialize e.g.
[TestInitialize]
public void Initialize()
{
var routeData = new RouteData();
_controller = new DepartmentSettingsController
{
ControllerContext = FakeControllerContext(routeData)
};
SiteMaps.Loader = new Mock<ISiteMapLoader>().Object;
}
we get the same error MvcSiteMapProvider.MvcSiteMapException: The sitemap loader may only be set in the Application_Start event of Global.asax and must not be set again. Set the 'MvcSiteMapProvider_UseExternalDIContainer' in the AppSettings section of the web.config file to 'true' if you are using an external dependency injection container. at MvcSiteMapProvider.SiteMaps.set_Loader(ISiteMapLoader value)
Question - Where is the best place for SiteMaps.Loader = new Mock<ISiteMapLoader>().Object;
in the Unit Test, when you're testing multiple actions
Question - Is using the static var node = SiteMaps.Current.CurrentNode;
the best way to go in the controllers, or is there a better way of doing it (we use Unity)
Thanks for your help