我正在尝试使用NUnit对一些代码进行单元测试。我有一个方法:
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方法,并在以下位置崩溃:
IController controller = factory.CreateController(requestContext, controllerName);出现以下错误:
Controllers.WidgetControllerTests.CanCreateWidgetOnPage: System.Web.HttpException:'System.Web.Compilation.CompilationLock‘的类型初始值设定项引发异常。-> System.TypeInitializationException:'System.Web.Compilation.CompilationLock‘的类型初始值设定项引发异常。-> System.NullReferenceException :对象引用未设置为对象的实例。
我对单元测试/模拟相当陌生,有可能我并没有看到一些简单的东西。
下面是我目前正在运行的测试:
[Test]
public void Test()
{
HttpContextBase context = MvcMockHelpers.DynamicHttpContextBase();
string s = RenderExtensions.RenderAction<HomeController>(context, a => a.About());
Console.WriteLine(s);
Assert.IsNotNullOrEmpty(s);
}任何帮助都将不胜感激。
我已经将问题简化为这个简单的单元测试:
[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);
}发布于 2009-06-12 16:59:16
在尝试对我编写的控制器工厂进行单元测试时,我遇到了同样的问题。
该问题似乎来自于ControllerTypeCache试图在第一次调用时遍历所有关联的程序集,并使用BuildManager执行此操作。通过使用BuildManager属性与实例交互而不是直接耦合,DefaultControllerFactory在这方面看起来非常可扩展,但不幸的是,该属性被标记为内部。与我们其他人不同,MVC框架单元测试能够访问MVC程序集的内部。
在查看了MVCContrib如何对它们的控制器工厂进行单元测试之后,我发现它们正在使用一个扩展方法帮助器,该帮助器使用反射来访问私有属性,从而覆盖控制器缓存。
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类型添加到控制器类型缓存中
https://stackoverflow.com/questions/727181
复制相似问题