如何对我的asp.net-mvc控制器的OnActionExecuting方法进行单元测试?

时间:2009-02-26 18:04:13

标签: asp.net-mvc unit-testing

我已经覆盖了我的控制器的OnActionExecuting方法,根据执行的filterContext设置了一些内部状态。我该如何测试?方法本身受到保护,所以我假设我必须在调用堆栈中更高。

我需要使用哪些代码进行测试?

我正在使用mvc RC 1。

编辑:我也在使用nunit。

由于

3 个答案:

答案 0 :(得分:15)

您需要添加和使用私人访问者。右键单击控制器类,从菜单中选择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进行单元测试,则可能需要手动生成访问器。本质上,您创建一个包装类,通过等效的公共方法公开被测试类的私有/受保护方法,将测试中的类的实例传递给包装器,然后使用包装类中的反射来调用private / protected关于被测班的方法。

   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 });
       }
    }

答案 1 :(得分:4)

我最近有类似的问题,找不到令人满意的解决方案。所以我创建了自己的辅助函数来调用OnActionExecuted和OnActionExecuting。请参阅此处的代码http://mkramar.blogspot.com.au/2012/06/onactionexecuting-and-onactionexecuted.html

答案 2 :(得分:0)

我试图这样做,但我实际上想要测试自定义属性的结果,因为它应用于实际控制器。在我们的例子中,我们有一个授权属性,在控制器上设置属性,然后控制器使用属性。我们的代码看起来像这样:

// 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属性。这两者都练习自定义属性代码,并在更像“真实世界”的情况下测试控制器。