It's good that you can test at the wrong level, but its test makes sense. I mean, if I mark a method with the authorize attribute (Roles = "Superhero"), I don't need a test if I tagged it. What I (I think) want is to verify that the unauthorized user does not have access and that the authorized user is doing.
For an unauthorized user, run the following tests:
// Arrange var user = SetupUser(isAuthenticated, roles); var controller = SetupController(user); // Act SomeHelper.Invoke(controller => controller.MyAction()); // Assert Assert.AreEqual(401, controller.ControllerContext.HttpContext.Response.StatusCode, "Status Code");
Well, it's not easy, and it took me 10 hours, but here it is. I hope someone can take advantage of this or convince me to go to another profession. :) (BTW - I use rhino mock)
[Test] public void AuthenticatedNotIsUserRole_Should_RedirectToLogin() { // Arrange var mocks = new MockRepository(); var controller = new FriendsController(); var httpContext = FakeHttpContext(mocks, true); controller.ControllerContext = new ControllerContext { Controller = controller, RequestContext = new RequestContext(httpContext, new RouteData()) }; httpContext.User.Expect(u => u.IsInRole("User")).Return(false); mocks.ReplayAll(); // Act var result = controller.ActionInvoker.InvokeAction(controller.ControllerContext, "Index"); var statusCode = httpContext.Response.StatusCode; // Assert Assert.IsTrue(result, "Invoker Result"); Assert.AreEqual(401, statusCode, "Status Code"); mocks.VerifyAll(); }
Although this is not very useful without this helper function:
public static HttpContextBase FakeHttpContext(MockRepository mocks, bool isAuthenticated) { var context = mocks.StrictMock<HttpContextBase>(); var request = mocks.StrictMock<HttpRequestBase>(); var response = mocks.StrictMock<HttpResponseBase>(); var session = mocks.StrictMock<HttpSessionStateBase>(); var server = mocks.StrictMock<HttpServerUtilityBase>(); var cachePolicy = mocks.Stub<HttpCachePolicyBase>(); var user = mocks.StrictMock<IPrincipal>(); var identity = mocks.StrictMock<IIdentity>(); var itemDictionary = new Dictionary<object, object>(); identity.Expect(id => id.IsAuthenticated).Return(isAuthenticated); user.Expect(u => u.Identity).Return(identity).Repeat.Any(); context.Expect(c => c.User).PropertyBehavior(); context.User = user; context.Expect(ctx => ctx.Items).Return(itemDictionary).Repeat.Any(); context.Expect(ctx => ctx.Request).Return(request).Repeat.Any(); context.Expect(ctx => ctx.Response).Return(response).Repeat.Any(); context.Expect(ctx => ctx.Session).Return(session).Repeat.Any(); context.Expect(ctx => ctx.Server).Return(server).Repeat.Any(); response.Expect(r => r.Cache).Return(cachePolicy).Repeat.Any(); response.Expect(r => r.StatusCode).PropertyBehavior(); return context; }
Thus, you will receive confirmation that users who do not have a role do not have access. I tried to write a test to confirm the opposite, but after two hours of work in mvc plumbing, I will leave it for hand testers. (I instructed when I got to the VirtualPathProviderViewEngine.WTF class? I don’t want anything to do VirtualPath or Provider or ViewEngine altogether out of three!)
I am curious why this is so difficult in the supposedly “verifiable” structure.