Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing Custom Model Binder - Fake HttpContext Issue

I have the following unit test defined to test my model binder:

[TestMethod]
public void DateTime_Works() {
    // Arrange
    var controllerContext = FakeContext.GetAuthenticatedControllerContext(new Mock<Controller>().Object, "TestAdmin");

    var values = new NameValueCollection {
        { "Foo.Date", "12/02/1964" },
        { "Foo.Hour", "12" },
        { "Foo.Minute", "00" },
        { "Foo.Second", "00" }
    };

    var bindingContext = new ModelBindingContext() { ModelName = "Foo", ValueProvider = new NameValueCollectionValueProvider(values, null) };
    var binder = new DateAndTimeModelBinder();

    // Act
    var result = (DateTime)binder.BindModel(controllerContext, bindingContext);

    // Assert
    Assert.AreEqual(DateTime.Parse("1964-12-02 12:00:00"), result);
}

Here is the FakeContext class:

public static class FakeContext {
    public static HttpContextBase GetHttpContext(string username) {
        var context = new Mock<HttpContextBase>();
        context.SetupGet(ctx => ctx.Request.IsAuthenticated).Returns(!string.IsNullOrEmpty(username));

        return context.Object;
    }

    public static ControllerContext GetControllerContext(Controller controller) {
        return GetAuthenticatedControllerContext(controller, null);
    }

    public static ControllerContext GetAuthenticatedControllerContext(Controller controller, string username) {
        var httpContext = GetHttpContext(username);
        return new ControllerContext(httpContext, new RouteData(), controller);
    }
}

Within my model binder i call a utility method which has the following line in it:

HttpContext.Current.User.Identity.IsAuthenticated

This seems to always return false even when I pass a username in. I was wondering how the GetHttpContext method can be modified to mock this out aswell.

I'd appreciate the help. Thanks

like image 936
nfplee Avatar asked Oct 25 '22 04:10

nfplee


2 Answers

You are mocking the IsAuthenticated property of the Request and not of the User Identity. Your mock is indicating that the request has been authenticated, but has nothing to do with the identity authentication.

Changing your mock up a little should fix your problem.

var identityMock = new Mock<IIdentity>();
identityMock.SetupGet( i => i.IsAuthenticated ).Returns( !string.IsNullOrEmpty(username));

var userMock = new Mock<IPrincipal>();
userMock.SetupGet( u => u.Identity ). Returns( identityMock.Object );

var context = new Mock<HttpContextBase>();
context.SetupGet( ctx => ctx.User ).Returns( userMock.Object );

Edit The more I thought about it the more I felt these mocks needed to be setup seperatly

Note, I have not executed this code. It should get you what you need however.

MSDN for Request.IsAuthenticated http://msdn.microsoft.com/en-us/library/system.web.httprequest.isauthenticated.aspx

MSDN for User.Identity.IsAuthenticated http://msdn.microsoft.com/en-us/library/system.security.principal.iidentity.isauthenticated.aspx

Hope this helps.

like image 66
Brian Dishaw Avatar answered Oct 27 '22 11:10

Brian Dishaw


You could use Moq and follow the advice found here:

Moq: unit testing a method relying on HttpContext

like image 31
Jason Evans Avatar answered Oct 27 '22 10:10

Jason Evans