How to Unit Test a custom ModelBinder using Moq?

允我心安 提交于 2019-12-03 07:24:42

问题


I'm having some difficulty writing some Unit Tests to test a custom ModelBinder that I created. The ModelBinder I'm trying to Unit Test is the JsonDictionaryModelBinder that I posted here.

The problem I'm having is getting the Mocking all setup using Moq. I keep getting Null Exceptions due to the HttpContextBase not being Mocked correctly. I think.

Could someone help me figure out what I'm not doing correclty?

Here's a sample of the Unit Test I'm trying to write that doesn't work:

[TestMethod()]
public void BindModelTest()
{
    JsonDictionaryModelBinder target = new JsonDictionaryModelBinder();

    NameValueCollection nameValueCollection = new NameValueCollection() {
        {"First", "1"},
        {"Second", "2"},
        {"Name", "Chris"},
        {"jsonValues", "{id: 200, name: 'Chris'}"}
    };

    HttpContextBase httpContext = MockHelper.FakeHttpContext(HttpVerbs.Post, nameValueCollection);

    ControllerContext controllerContext =
        new ControllerContext(new RequestContext(httpContext, new RouteData()), new Mock<Controller>().Object);


    Predicate<string> predicate = propertyName => (propertyName == "jsonValues");
    ModelBindingContext bindingContext = new ModelBindingContext()
    {
        Model = null,
        ModelType = typeof(JsonDictionary),
        ModelState = new ModelStateDictionary(),
        PropertyFilter = predicate,
        ValueProvider = new Dictionary<string, ValueProviderResult>() { { "foo", null } }
    };

    //object expected = null; // TODO: Initialize to an appropriate value
    var actual = target.BindModel(controllerContext, bindingContext) as JsonDictionary;

    Assert.IsNotNull(actual);

    Assert.AreEqual("Chris", actual["name"]);
    //Assert.AreEqual(expected, actual);
    Assert.Inconclusive("Verify the correctness of this test method.");
}

Here's the "FakeHttpContext" method used above:

public static class MockHelper
{
    public static HttpContextBase FakeHttpContext(HttpVerbs verbs, NameValueCollection nameValueCollection)
    {
        var httpContext = new Mock<HttpContextBase>();

        var request = new Mock<HttpRequestBase>();
        request.Setup(c => c.Form).Returns(nameValueCollection);
        request.Setup(c => c.QueryString).Returns(nameValueCollection);

        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var server = new Mock<HttpServerUtilityBase>();
        httpContext.Setup(c => c.Request).Returns(request.Object);

        var u = verbs.ToString().ToUpper();
        httpContext.Setup(c => c.Request.RequestType).Returns(
            verbs.ToString().ToUpper()
        );

        httpContext.Setup(c => c.Response).Returns(response.Object);
        httpContext.Setup(c => c.Server).Returns(server.Object);
        httpContext.Setup(c => c.User.Identity.Name).Returns("testclient");
        return httpContext.Object;
    }
}

回答1:


The culprit is this line:

httpContext.Setup(c => c.Request.RequestType).Returns(
                verbs.ToString().ToUpper()
            );

This is technically a second Setup on the Request object, and it is wiping out the original Setup, even though you're going "past" it in the object hierarchy. I'm not sure if this is a bug in Moq or desired behaviour, I've run into this before as well and haven't gotten around to checking it out.

You can solve it by moving that line to where you're setting up your request above, and setting it up directly, rather than by going through the httpContext. So,

request.Setup(c => c.RequestType).Returns(verbs.ToString().ToUpper());

I also notice that the "var u" that you declare is not being used ;)



来源:https://stackoverflow.com/questions/1080997/how-to-unit-test-a-custom-modelbinder-using-moq

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!