【发布时间】:2013-12-31 03:30:20
【问题描述】:
我已经重写了我的控制器的 OnActionExecuting 方法,以根据正在执行的 filterContext 设置一些内部状态。我该如何测试这个?该方法本身是受保护的,所以我认为我必须在调用堆栈中更高。
我需要什么代码来测试这个?
我正在使用 mvc RC 1。
编辑:我也在使用 nunit。
谢谢
【问题讨论】:
我已经重写了我的控制器的 OnActionExecuting 方法,以根据正在执行的 filterContext 设置一些内部状态。我该如何测试这个?该方法本身是受保护的,所以我认为我必须在调用堆栈中更高。
我需要什么代码来测试这个?
我正在使用 mvc RC 1。
编辑:我也在使用 nunit。
谢谢
【问题讨论】:
您需要添加和使用私有访问器。右键单击您的控制器类并从菜单中选择Create Private Accessors 并将它们添加到您的测试项目中。进入测试项目后,创建控制器,然后为其创建访问器。该方法应该在访问器上可用。这是我自己的代码中的示例测试:
/// <summary>
///A test for OnActionExecuting
///</summary>
[TestMethod()]
[ExpectedException( typeof( InvalidOperationException ) )]
public void OnActionExecutingWindowsIdentityTest()
{
var identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal( identity );
var httpContext = MockRepository.GenerateStub<HttpContextBase>();
httpContext.User = principal;
var actionDescriptor = MockRepository.GenerateStub<ActionDescriptor>();
RouteData routeData = new RouteData();
BaseController controller = new BaseController();
BaseController_Accessor accessor = new BaseController_Accessor( new PrivateObject( controller ) );
ControllerContext controllerContext = MockRepository.GenerateStub<ControllerContext>( httpContext, routeData, controller );
ActionExecutingContext filterContext = new ActionExecutingContext( controllerContext, actionDescriptor, new Dictionary<string, object>() );
accessor.OnActionExecuting( filterContext );
}
编辑:如果您没有使用 MSTest 进行单元测试,则可能必须手动生成访问器。本质上,您创建一个包装器类,通过等效的公共方法公开被测类的私有/受保护方法,将被测类的实例传递给包装器,然后使用包装器类的反射来调用私有/受保护的方法被测类的方法。
public class MyClass
{
protected void DoSomething( int num )
{
}
}
public class MyClass_accessor
{
private MyClass privateObj;
public MyClass_accessor( MyClass obj )
{
this.privateObj = obj;
}
public void DoSomething( int num )
{
MethodInfo info = privateObj.GetType()
.GetMethod("DoSomething",
BindingFlags.NonPublic
| BindingFlags.Instance );
info.Invoke(obj,new object[] { num });
}
}
【讨论】:
我最近遇到了类似的问题,找不到令人满意的解决方案。所以我创建了我自己的辅助函数来调用 OnActionExecuted 和 OnActionExecuting。在此处查看代码http://mkramar.blogspot.com.au/2012/06/onactionexecuting-and-onactionexecuted.html
【讨论】:
我试图这样做,但实际上我想测试自定义属性的结果,因为它应用于实际控制器。在我们的例子中,我们有一个在控制器上设置属性的授权属性,然后控制器使用这些属性。我们的代码如下所示:
// Create the controller to test
PortalController controller = new PortalController();
var method = typeof(PortalController);
var attribute = method.GetCustomAttributes(typeof(OrganizationContextFilter),true).Cast<OrganizationContextFilter>().SingleOrDefault();
// Set the controller Context with our fake objects on it
controller.ControllerContext = this.GetDefaultControllerMock(controller);
// Execute the Organization Context Filter
var actionDescriptor = new Mock<ActionDescriptor>();
var context = Mock.Get(actionDescriptor.Object);
context.Setup(s => s.ControllerDescriptor).Returns(new Mock<ControllerDescriptor>().Object);
// Use the current controller Context
ActionExecutingContext filterContext = new ActionExecutingContext( controller.ControllerContext, actionDescriptor.Object, new Dictionary<string, object>() );
attribute.OnActionExecuting(filterContext);
// We have to use this one, because it has the result of the Attribute execution
PortalController pc = filterContext.Controller as PortalController;
ActionResult result = pc.MethodToTest(); // Call the controller that had OnActionExecuting results
这样做的好处是我们实际上在我们实际测试的控制器上执行了自定义 MVC 属性。这既练习了自定义属性代码,又在更像“真实世界”的情况下测试了控制器。
【讨论】: