因此控制器上下文取决于一些asp.net内部.有什么方法可以干净地模拟这些单元测试?当我只需要例如Request.HttpMethod来返回"GET"时,似乎很容易堵塞大量设置的测试.
我在网上看过一些例子/助手,但有些已经过时了.认为这将是保持最新和最伟大的好地方.
我正在使用最新版本的犀牛嘲笑
使用MoQ看起来像这样:
var request = new Mock(); request.Expect(r => r.HttpMethod).Returns("GET"); var mockHttpContext = new Mock (); mockHttpContext.Expect(c => c.Request).Returns(request.Object); var controllerContext = new ControllerContext(mockHttpContext.Object , new RouteData(), new Mock ().Object);
我认为Rhino Mocks语法类似.
这是一个使用MsTest和Moq的示例单元测试类,它可以模拟HttpRequest和HttpResponse对象.(.NET 4.0,ASP.NET MVC 3.0)
控制器操作从请求获取值并在响应对象中设置http标头.可以以类似的方式模拟其他http上下文对象
[TestClass] public class MyControllerTest { protected MockHttpContextBaseMock; protected Mock HttpRequestMock; protected Mock HttpResponseMock; [TestInitialize] public void TestInitialize() { HttpContextBaseMock = new Mock (); HttpRequestMock = new Mock (); HttpResponseMock = new Mock (); HttpContextBaseMock.SetupGet(x => x.Request).Returns(HttpRequestMock.Object); HttpContextBaseMock.SetupGet(x => x.Response).Returns(HttpResponseMock.Object); } protected MyController SetupController() { var routes = new RouteCollection(); var controller = new MyController(); controller.ControllerContext = new ControllerContext(HttpContextBaseMock.Object, new RouteData(), controller); controller.Url = new UrlHelper(new RequestContext(HttpContextBaseMock.Object, new RouteData()), routes); return controller; } [TestMethod] public void IndexTest() { HttpRequestMock.Setup(x => x["x"]).Returns("1"); HttpResponseMock.Setup(x => x.AddHeader("name", "value")); var controller = SetupController(); var result = controller.Index(); Assert.AreEqual("1", result.Content); HttpRequestMock.VerifyAll(); HttpResponseMock.VerifyAll(); } } public class MyController : Controller { public ContentResult Index() { var x = Request["x"]; Response.AddHeader("name", "value"); return Content(x); } }
这是Jason链接的片段.它与菲尔的方法相同,但使用犀牛.
注意:mockHttpContext.Request被存根以在 mockRequest的内部被删除之前返回mockRequest .我相信这个订单是必需的.
// create a fake web context var mockHttpContext = MockRepository.GenerateMock(); var mockRequest = MockRepository.GenerateMock (); mockHttpContext.Stub(x => x.Request).Return(mockRequest); // tell the mock to return "GET" when HttpMethod is called mockRequest.Stub(x => x.HttpMethod).Return("GET"); var controller = new AccountController(); // assign the fake context var context = new ControllerContext(mockHttpContext, new RouteData(), controller); controller.ControllerContext = context; // act ...
这个程序似乎在MVC2中略有改变(我正在使用RC1).如果动作需要特定的方法([HttpPost]
,[HttpGet]
),Phil Haack的解决方案对我不起作用.在Reflector中浏览,看起来验证这些属性的方法已经改变.MVC现在检查request.Headers
,request.Form
和request.QueryString
一个X-HTTP-Method-Override
值.
如果为这些属性添加模拟,它可以工作:
var request = new Mock(); request.Setup(r => r.HttpMethod).Returns("POST"); request.Setup(r => r.Headers).Returns(new NameValueCollection()); request.Setup(r => r.Form).Returns(new NameValueCollection()); request.Setup(r => r.QueryString).Returns(new NameValueCollection()); var mockHttpContext = new Mock (); mockHttpContext.Expect(c => c.Request).Returns(request.Object); var controllerContext = new ControllerContext(mockHttpContext.Object, new RouteData(), new Mock ().Object);
或者您可以使用Typemock Isolator执行此操作,而无需发送任何假控制器:
Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get");