Saturday, February 5, 2011

Unit testing Controller.Initialize

I am setting the thread culture to the culture sent via a cookie on the HttpRequest in the initialize method of a base controller I have created. I now want to create a unit test for this functionality.

In the test I have created a mock HttpContext and added the Cookie. Using this and a routeData helper, I create a RequestContext. Then I create a new controller and call Execute on it passing in the RequestContext.

I first hit a problem regarding TempData and SessionState, which I have fixed by setting the TempData and creating an EmptyTempDataProvider on the controller.

Then I had a problem with the VirtualPathProviderViewengine, which I fixed by creating a VoidActionInvoker.

Is this the best way to test the initialize method? Any doing anything similar and willing to share some code?

Thanks, Jon

namespace MyApp.UnitTests {
[TestClass]
public class ControllerTests {
 [TestInitialize]
 public void Setup() {
  RouteTable.Routes.Clear();
  MyApp.MvcApplication.RegisterRoutes(RouteTable.Routes);
 }

 [TestMethod]
 public void Thread_culture_should_be_set_to_cookie_culture() {
  // Arrange
  var context = HttpMockHelper.FakeHttpContext();
  context.Request.Cookies.Add(new HttpCookie(CultureService.CookieName, "nl-NL"));
  var reqContext = new RequestContext(context, "~/Home/Landing".Route());
  var controller = new HomeController {
   TempData = new TempDataDictionary(),
   TempDataProvider = new EmptyTempDataProvider(),
   ActionInvoker = new VoidActionInvoker()
  };

  // Act
  (controller as IController).Execute(reqContext);

  // Assert
  Assert.AreEqual("nl-NL", Thread.CurrentThread.CurrentCulture.Name);
 }
}

internal class VoidActionInvoker : ControllerActionInvoker {
 protected override ActionExecutedContext InvokeActionMethodWithFilters(System.Reflection.MethodInfo methodInfo, IDictionary<string, object> parameters, IList<IActionFilter> filters) {
  return new ActionExecutedContext(this.ControllerContext, false, null);
 }

 protected override void InvokeActionResult(ActionResult actionResult) {
 }
}

internal class EmptyTempDataProvider : ITempDataProvider {
 public void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values) {
 }

 public IDictionary<string, object> LoadTempData(ControllerContext controllerContext) {
  return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
 }
}
}
  • Sounds right to me, the initialize method takes a parameter for the requestcontext that requires an HttpContext, if I've got your post right you're mocking these objects and adding the values you want to test with and then ensuring that your method works correctly. Sounds exactly like what I would do. I wouldn't mind seeing some of the code though.

    Edit: Your tests look good to me.

    From Odd

0 comments:

Post a Comment