模拟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);