模拟Asp.net-mvc控制器上下文
时间:2020-03-05 18:44:29 来源:igfitidea点击:
因此,控制器上下文取决于一些asp.net内部。有什么方法可以干净地模拟这些以进行单元测试?当我只需要例如Request.HttpMethod返回" GET"时,似乎很容易用大量设置阻塞测试。
我已经在网上看到了一些例子/帮助者,但其中有些是过时的。认为这将是保持最新和最佳状态的好地方。
我正在使用最新版本的犀牛模拟
解决方案
回答
使用最小起订量看起来像这样:
var request = new Mock<HttpRequestBase>(); request.Expect(r => r.HttpMethod).Returns("GET"); var mockHttpContext = new Mock<HttpContextBase>(); mockHttpContext.Expect(c => c.Request).Returns(request.Object); var controllerContext = new ControllerContext(mockHttpContext.Object , new RouteData(), new Mock<ControllerBase>().Object);
我认为Rhino Mocks的语法相似。
回答
我发现冗长的模拟程序会产生太多摩擦。
我们发现在实际项目中使用ASP.NET MVC的最佳方法是将HttpContext抽象到一个简单的IWebContext接口。然后,我们可以轻松模拟IWebContext。
这是一个例子
回答
这是Jason链接的摘录。它与Phil的方法相同,但使用的是犀牛。
注意:在嘲笑了mockRequest的内部之前,将嘲笑mockHttpContext.Request返回mockRequest。我相信此命令是必需的。
// create a fake web context var mockHttpContext = MockRepository.GenerateMock<HttpContextBase>(); var mockRequest = MockRepository.GenerateMock<HttpRequestBase>(); 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 ...
回答
我已经完成了这个规格
public abstract class Specification <C> where C: Controller { protected C controller; HttpContextBase mockHttpContext; HttpRequestBase mockRequest; protected Exception ExceptionThrown { get; private set; } [SetUp] public void Setup() { mockHttpContext = MockRepository.GenerateMock<HttpContextBase>(); mockRequest = MockRepository.GenerateMock<HttpRequestBase>(); mockHttpContext.Stub(x => x.Request).Return(mockRequest); mockRequest.Stub(x => x.HttpMethod).Return("GET"); EstablishContext(); SetHttpContext(); try { When(); } catch (Exception exc) { ExceptionThrown = exc; } } protected void SetHttpContext() { var context = new ControllerContext(mockHttpContext, new RouteData(), controller); controller.ControllerContext = context; } protected T Mock<T>() where T: class { return MockRepository.GenerateMock<T>(); } protected abstract void EstablishContext(); protected abstract void When(); [TearDown] public virtual void TearDown() { } }
果汁在这里
[TestFixture] public class When_invoking_ManageUsersControllers_Update :Specification <ManageUsersController> { private IUserRepository userRepository; FormCollection form; ActionResult result; User retUser; protected override void EstablishContext() { userRepository = Mock<IUserRepository>(); controller = new ManageUsersController(userRepository); retUser = new User(); userRepository.Expect(x => x.GetById(5)).Return(retUser); userRepository.Expect(x => x.Update(retUser)); form = new FormCollection(); form["IdUser"] = 5.ToString(); form["Name"] = 5.ToString(); form["Surename"] = 5.ToString(); form["Login"] = 5.ToString(); form["Password"] = 5.ToString(); } protected override void When() { result = controller.Edit(5, form); } [Test] public void is_retrieved_before_update_original_user() { userRepository.AssertWasCalled(x => x.GetById(5)); userRepository.AssertWasCalled(x => x.Update(retUser)); } }
请享用
回答
或者,我们可以使用Typemock隔离器执行此操作,而无需完全发送伪造的控制器:
Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get");
回答
在MVC2中,此过程似乎已稍有更改(我正在使用RC1)。如果操作需要特定的方法([HttpPost],[HttpGet]),Phil Haack的解决方案将对我不起作用。在Reflector中四处摸索,看来验证这些属性的方法已更改。 MVC现在会检查" request.Headers"," request.Form"和" request.QueryString"中是否有" X-HTTP-Method-Override"值。
如果我们为这些属性添加模拟,它将起作用:
var request = new Mock<HttpRequestBase>(); 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<HttpContextBase>(); mockHttpContext.Expect(c => c.Request).Returns(request.Object); var controllerContext = new ControllerContext(mockHttpContext.Object, new RouteData(), new Mock<ControllerBase>().Object);