使用Moq和Mvc伪造Http上下文

时间:2012-09-17 08:12:16

标签: moq

我正在尝试伪造http上下文以测试Controller。我的环境是MVC 3和Moq 4。 到目前为止,我尝试了一些选项,包括:

一个。

var searchController = new MySearchController(_mockResolver.Object.Resolve<IConfiguration>());
var mockContext = new Mock<ControllerContext>();
searchController.ControllerContext = mockContext.Object;
var result = searchController.Render();

var searchController = new MopSearchController(_mockResolver.Object.Resolve<IConfiguration>());
searchController.MockControllerContext();
var result = searchController.Render();

public static class MockHttpHelper
{
    public static Mock<HttpContextBase> MockControllerContext(
                                this Controller controller, string path = null)
    {
        var mockHttpCtx = MockHttpHelper.MockHttpContext(path);
        var requestCtx = new RequestContext(mockHttpCtx.Object, new RouteData());
        var controllerCtx = new ControllerContext(requestCtx, controller);
        controller.ControllerContext = controllerCtx;
        return mockHttpCtx;
    }

    public static Mock<HttpContextBase> MockHttpContext(string path)
    {
        var mockHttpCtx = new Mock<HttpContextBase>();
        var mockReq = new Mock<HttpRequestBase>();

        mockReq.SetupGet(x => x.RequestType).Returns("GET");
        mockReq.SetupGet(req => req.Form).Returns(new NameValueCollection());
        mockReq.SetupGet(req => req.QueryString).Returns(new NameValueCollection());

        mockHttpCtx.SetupGet(x => x.Request).Returns(mockReq.Object);

        return mockHttpCtx;
    }
}

这些都不起作用,我在下面得到了例外。有人能指出我的工作方向吗?我在网上围绕同一主题看到了不少问题,但考虑到日期(2008-2010的帖子)和MVC版本(即1和2),我觉得我错过了某些东西/或试图嘲笑更多比我在MVC3中需要的那样。

System.NullReferenceException : Object reference not set to an instance of an object.
at System.Web.Mvc.ChildActionValueProviderFactory.GetValueProvider(ControllerContext controllerContext)
at System.Web.Mvc.ValueProviderFactoryCollection.<>c__DisplayClassc.<GetValueProvider>b__7(ValueProviderFactory factory)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList(IEnumerable`1 source)
at System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)
at System.Web.Mvc.Controller.TryUpdateModel(TModel model)

由于

1 个答案:

答案 0 :(得分:0)

是的,正如您所指出的那样,您真正缺少的是设置Controller的ValueProvider。即使您将此控制器与Get操作但没有Post操作一起使用,Controller仍会在创建时实例化ValueProvider,因此您需要在测试场景中执行相同的操作。这是我在测试控制器时使用的基类。我使用NBehave's NUnit wrapper进行单元测试,因此如果您愿意,请忽略SpecBase引用

public abstract class MvcSpecBase<T> : SpecBase<T> where T : Controller
{
    protected T Controller { get; set; }

    protected string RelativePath = string.Empty;

    protected string AbsolutePath = string.Empty;

    protected void InitialiseController(T controller, NameValueCollection collection, params string[] routePaths)
    {
        Controller = controller;
        var routes = new RouteCollection();
        RouteConfig.RegisterRoutes(routes);
        var httpContext = ContextHelper.FakeHttpContext(RelativePath, AbsolutePath, routePaths);
        var context = new ControllerContext(new RequestContext(httpContext, new RouteData()), Controller);
        var urlHelper = new UrlHelper(new RequestContext(httpContext, new RouteData()), routes);
        Controller.ControllerContext = context;
        Controller.ValueProvider = new NameValueCollectionValueProvider(collection, CultureInfo.CurrentCulture);
        Controller.Url = urlHelper;
    }
}

然后,在您的测试中,创建您的控制器,然后调用此行:

InitialiseController(controller, new FormCollection());