0

我正在尝试伪造 http 上下文来测试控制器。我的环境是 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)

谢谢

4

1 回答 1

0

是的,正如您所指出的,您真正缺少的只是设置控制器的ValueProvider. 即使您将此控制器与 Get 操作一起使用但没有 Post 操作,控制器仍会ValueProvider在创建时实例化,因此您需要在测试场景中执行相同的操作。这是我在测试控制器时使用的基类。我使用NBehave 的 NUnit 包装器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());
于 2013-02-08T23:22:50.513 回答