John Dough John Dough - 2 months ago 25
C# Question

Can't seem to set object when mocking HttpApplicationState with Moq

I have an action filter which is setting an object in the HttpApplicationState of the HttpContext of the filter context. I would like to have this functionality in a unit test but for some reason the object is not being set in the underlying NameObjectCollectionBase from which HttpApplicationState derives.

I know the functionality works because when I run the MVC application it works as expected.

How can I set up my test to get it to set objects in the application state? Im using Moq and here is some of the code so far. It fails on

Asset.IsNotNull(context.HttpContext.Application["config"]);


Here is the code.

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
ControllerBase controller = filterContext.Controller;
if (!(controller is ApplicationController))
return;

ApplicationController applicationController = (ApplicationController) controller;

IDictionary<string, string> config;

// Loads the view configuration values.
if (filterContext.HttpContext.Application["config"] == null)
{
config = applicationController.ApplicationService.GetConfiguration();
filterContext.HttpContext.Application["config"] = config;
}
else
{
config = (IDictionary<string, string>) filterContext.HttpContext.Application["config"];
}

applicationController.ViewBag.BlogTitle = AddConfigurationValueToViewBag("BlogTitle", config);

}


Here's the test so far.

[TestMethod]
public void ApplicationAttribute_OnActionExecuted_SetsConfigurationDctionaryInAppicationCache()
{
// Arrange
Mock<HttpContextBase> httpContext = new Mock<HttpContextBase>();

var mockApplicationState = new Mock<HttpApplicationStateBase>();
httpContext.Setup(h => h.Application).Returns(mockApplicationState.Object);

ApplicationController applicationController = new BlogController(null, null, MocksAndStubs.CreateMockApplicationService());

Mock<ActionExecutedContext> actionExecutedContext = new Mock<ActionExecutedContext>();
actionExecutedContext.SetupGet(c => c.HttpContext).Returns(httpContext.Object);
actionExecutedContext.SetupGet(c => c.Controller).Returns(applicationController);

// Act
ApplicationAttribute applicationAttribute = new ApplicationAttribute();
ActionExecutedContext context = actionExecutedContext.Object;
applicationAttribute.OnActionExecuted(context);

// Assert
Assert.IsNotNull(context.HttpContext.Application["config"]);
}

Answer

It looks like you are expecting your mock object to more or less act like the real object. It doesn't work that way; the mock will only do what you tell it to do, nothing more, nothing less. If you don't tell the mock to return something specific when you call . . .

context.HttpContext.Application["config"]

. . . then it simply won't. If you did set the mock up to return something specific, it would defeat the purpose of your test.

Without any additional understanding or your situation (the "what" and "why" of your testing stategy), it looks like you are trying to ensure that the set on the application state gets called. I would recommend doing a mockApplicationState.Verify() as your assertion to test that the set happened, instead of testing the resulting state of the object itself.

Edit: Verify() allows you to assert/ensure that a method (or property method) was called, with or without conditions. This should get you started:

http://code.google.com/p/moq/wiki/QuickStart#Verification

So your verify would look something like (totally untested!):

mockApplicationState.Verify(x => x["config"] == [expected value], Times.Once());

This basically says fail the test if the mockApplicationState["config"] got set to the expected value less than once or more than once.

I'm assuming HttpApplicationStateBase is not sealed. If it is then the above may throw an exception.

Comments