首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ASP.NET Mvc - System.Web.Compilation.CompilationLock

ASP.NET Mvc - System.Web.Compilation.CompilationLock
EN

Stack Overflow用户
提问于 2009-04-07 19:08:32
回答 1查看 3.3K关注 0票数 7

我正在尝试使用NUnit对一些代码进行单元测试。我有一个方法:

代码语言:javascript
复制
    public static string RenderRoute(HttpContextBase context, RouteValueDictionary values)
    {
        var routeData = new RouteData();
        foreach (var kvp in values)
        {
            routeData.Values.Add(kvp.Key, kvp.Value);
        }

        string controllerName = routeData.GetRequiredString("controller");
        var requestContext = new RequestContext(context, routeData);
        IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
        IController controller = factory.CreateController(requestContext, controllerName);

        var ActionInvoker = new ControllerActionInvoker();
        var controllerContext = new ControllerContext(requestContext, (ControllerBase)controller);
        ((ControllerBase)controller).ControllerContext = controllerContext;

        string actionName = routeData.GetRequiredString("action");

        Action action = delegate { ActionInvoker.InvokeAction(controllerContext, actionName); };

        return new BlockRenderer(context).Capture(action);
    }

我的默认控制器工厂是来自MvcContrib的StructureMap控制器工厂。我还使用了来自MvcContrib的MvcMockHelpers来帮助我模拟HttpContextBase。

我尝试测试的控制器调用上面的RenderRoute方法,并在以下位置崩溃:

代码语言:javascript
复制
IController controller = factory.CreateController(requestContext, controllerName);

出现以下错误:

Controllers.WidgetControllerTests.CanCreateWidgetOnPage: System.Web.HttpException:'System.Web.Compilation.CompilationLock‘的类型初始值设定项引发异常。-> System.TypeInitializationException:'System.Web.Compilation.CompilationLock‘的类型初始值设定项引发异常。-> System.NullReferenceException :对象引用未设置为对象的实例。

我对单元测试/模拟相当陌生,有可能我并没有看到一些简单的东西。

下面是我目前正在运行的测试:

代码语言:javascript
复制
    [Test]
    public void Test()
    {
        HttpContextBase context = MvcMockHelpers.DynamicHttpContextBase();
        string s = RenderExtensions.RenderAction<HomeController>(context, a => a.About());

        Console.WriteLine(s);
        Assert.IsNotNullOrEmpty(s);
    }

任何帮助都将不胜感激。

我已经将问题简化为这个简单的单元测试:

代码语言:javascript
复制
    [Test]
    public void Test2()
    {
        HttpContextBase context = MvcMockHelpers.DynamicHttpContextBase();
        var routeData = new RouteData();
        routeData.Values.Add("Controller", "Home");
        routeData.Values.Add("Action", "About");


        string controllerName = routeData.GetRequiredString("controller");
        var requestContext = new RequestContext(context, routeData);
        IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
        IController controller = factory.CreateController(requestContext, controllerName);

        Assert.IsNotNull(controller);
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2009-06-12 16:59:16

在尝试对我编写的控制器工厂进行单元测试时,我遇到了同样的问题。

该问题似乎来自于ControllerTypeCache试图在第一次调用时遍历所有关联的程序集,并使用BuildManager执行此操作。通过使用BuildManager属性与实例交互而不是直接耦合,DefaultControllerFactory在这方面看起来非常可扩展,但不幸的是,该属性被标记为内部。与我们其他人不同,MVC框架单元测试能够访问MVC程序集的内部。

在查看了MVCContrib如何对它们的控制器工厂进行单元测试之后,我发现它们正在使用一个扩展方法帮助器,该帮助器使用反射来访问私有属性,从而覆盖控制器缓存。

代码语言:javascript
复制
using System;
using System.Linq;
using System.Reflection;
using System.Web.Mvc;

public static class ControllerFactoryTestExtension
{
    private static readonly PropertyInfo _typeCacheProperty;
    private static readonly FieldInfo _cacheField;

    static ControllerFactoryTestExtension()
    {
        _typeCacheProperty = typeof(DefaultControllerFactory).GetProperty("ControllerTypeCache", BindingFlags.Instance | BindingFlags.NonPublic);
        _cacheField = _typeCacheProperty.PropertyType.GetField("_cache", BindingFlags.NonPublic | BindingFlags.Instance);
    }

    /// <summary>
    /// Replaces the cache field of a the DefaultControllerFactory's ControllerTypeCache.
    /// This ensures that only the specified controller types will be searched when instantiating a controller.
    /// As the ControllerTypeCache is internal, this uses some reflection hackery.
    /// </summary>
    public static void InitializeWithControllerTypes(this IControllerFactory factory, params Type[] controllerTypes)
    {
        var cache = controllerTypes
            .GroupBy(t => t.Name.Substring(0, t.Name.Length - "Controller".Length), StringComparer.OrdinalIgnoreCase)
            .ToDictionary(g => g.Key, g => g.ToLookup(t => t.Namespace ?? string.Empty, StringComparer.OrdinalIgnoreCase), StringComparer.OrdinalIgnoreCase);

        var buildManager = _typeCacheProperty.GetValue(factory, null);
        _cacheField.SetValue(buildManager, cache);
    }
}

在将其添加到我的单元测试项目之后,我能够使用controllerFactory.InitializeWithControllerTypes(new[] {typeof(MockController)});将我自己的MockController类型添加到控制器类型缓存中

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/727181

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档