【问题标题】:Testing custom ModelBinder against HTTP context in ASP.NET MVC (1.0)在 ASP.NET MVC (1.0) 中针对 HTTP 上下文测试自定义 ModelBinder
【发布时间】:2010-10-02 20:50:17
【问题描述】:
我正在尝试对自定义模型绑定器进行单元测试 - 具体来说,我想看看它如何响应在 Request.Form 和 Request.QueryString 集合中提交的各种(可能是冲突的)值 - 即如果我提交一个值在表单中,另一个在查询字符串中(是的,是的,我知道,这是邪恶的,但我想要测试覆盖以防万一)我可以准确地验证哪个将绑定到模型。
为了做到这一点,我想模拟/伪造 HTTP 上下文,然后调用模型绑定器并查看实际返回的内容。我看过几篇关于测试 ModelBinders 的帖子,但它们都使用自定义的 ValueProvider,而我实际上想测试 MVC 与 Form/Request 集合交互的方式。
有什么想法可以模拟这些集合,然后在我的单元测试中基于这个模拟的 HTTP 上下文使我的模型绑定器使用“默认”ValueProvider?这是在 ASP.NET MVC 1.0 上。谢谢。
【问题讨论】:
标签:
asp.net-mvc
unit-testing
mocking
httpcontext
modelbinders
【解决方案1】:
搞定 - 解决方案是模拟 ControllerContext,然后构造一个新的 System.Web.Mvc.ValueProviderDictionary 并将模拟的控制器上下文传递给构造函数,如下所示:
[Test]
public void WorkFolder_Id_Is_Parsed_From_QueryString() {
var fakeControllerContext = GetControllerContext(null, "folder=10");
var bindingContext = new ModelBindingContext() {
ValueProvider = new System.Web.Mvc.ValueProviderDictionary(fakeControllerContext),
ModelName = "menu",
FallbackToEmptyPrefix = true
};
var binder = new RenewalMenuPostModelBinder();
var model = binder.BindModel(fakeControllerContext, bindingContext) as RenewalMenuPostModel;
Assert.That(model is RenewalMenuPostModel);
Assert.That(model.WorkFolderId.HasValue);
Assert.That(model.WorkFolderId.Value == 10);
}
private static ControllerContext GetControllerContext(NameValueCollection form, string queryString) {
Mock<HttpRequestBase> mockRequest = new Mock<HttpRequestBase>();
mockRequest.Expect(r => r.Form).Returns(form);
var queryStringCollection = HttpUtility.ParseQueryString(queryString);
mockRequest.Expect(r => r.QueryString).Returns(queryStringCollection);
Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Expect(c => c.Request).Returns(mockRequest.Object);
return new ControllerContext(mockHttpContext.Object, new RouteData(), new Mock<ControllerBase>().Object);
}