如何使用 Moq 对自定义 ModelBinder 进行单元测试?
我在编写一些单元测试来测试我创建的自定义 ModelBinder 时遇到一些困难。 我尝试进行单元测试的 ModelBinder 是我发布的 JsonDictionaryModelBinder 此处。
我遇到的问题是使用起订量进行模拟所有设置。 由于 HttpContextBase 没有被正确模拟,我不断收到 Null 异常。 我认为。
有人可以帮我弄清楚我没有做正确的事情吗?
这是我试图编写的单元测试示例,但它不起作用:
[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.");
}
这是上面使用的“FakeHttpContext”方法:
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;
}
}
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;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
罪魁祸首是这一行:
从技术上讲,这是 Request 对象上的第二个
Setup
,它会清除原始的Setup
,即使您要“过去”它在对象层次结构中。 我不确定这是否是起订量中的错误或期望的行为,我以前也遇到过这个问题,但还没有抽出时间来检查它。您可以通过将该行移动到上面设置请求的位置并直接设置来解决此问题,而不是通过 httpContext。 所以,
我还注意到您声明的“var u”没有被使用;)
The culprit is this line:
This is technically a second
Setup
on the Request object, and it is wiping out the originalSetup
, 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,
I also notice that the "var u" that you declare is not being used ;)