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

时间:2021-12-29 01:39:43

I've overridden my controller's OnActionExecuting method to set some internal state based on the executing filterContext. How do I test this? The method itself is protected so I assume I'll have to go higher up in the call stack.

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

What code do I need to test this?

我需要用什么代码来测试它?

I'm using mvc RC 1.

我正在使用mvc RC 1。

Edit: I'm also using nunit.

编辑:我也在使用nunit。

Thanks

谢谢

3 个解决方案

#1


15  

You need to add and use a Private Accessor. Right click in your controller class and choose Create Private Accessors from the menu and add them to your test project. Once in your test project, create your controller, then create an accessor for it. The method should be available on the accessor. Here's a sample test from my own code:

您需要添加和使用私人访问者。右键单击控制器类,然后从菜单中选择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 );

}

EDIT: If you aren't using MSTest for your unit tests, you may have to generate the accessors by hand. Essentially, you make a wrapper class that exposes the private/protected methods of the class under test via equivalent public methods, pass an instance of the class under test to the wrapper, and then use reflection from the wrapper class to invoke the private/protected method on the class under test.

编辑:如果您没有使用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 });
       }
    }

#2


4  

I recently had a similar problem and could not find satisfying solution. So I created my own helper function that invokes OnActionExecuted and OnActionExecuting. See code here http://mkramar.blogspot.com.au/2012/06/onactionexecuting-and-onactionexecuted.html

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

#3


0  

I was trying to do this, but I actually wanted to test the outcome of the custom attribute as it applied to the actual controller. In our case we had an authorization attribute that set properties on the controller, the controller then used the properties. Our code looks something like this:

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

// 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

The benefit of this is that we actually execute the custom MVC attribute on the controller we are actually testing. This both exercises the custom attribute code and tests the controller in a situation that is more like the "real world".

这样做的好处是我们实际上在我们实际测试的控制器上执行自定义MVC属性。这两者都练习自定义属性代码并在更像“真实世界”的情况下测试控制器。

#1


15  

You need to add and use a Private Accessor. Right click in your controller class and choose Create Private Accessors from the menu and add them to your test project. Once in your test project, create your controller, then create an accessor for it. The method should be available on the accessor. Here's a sample test from my own code:

您需要添加和使用私人访问者。右键单击控制器类,然后从菜单中选择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 );

}

EDIT: If you aren't using MSTest for your unit tests, you may have to generate the accessors by hand. Essentially, you make a wrapper class that exposes the private/protected methods of the class under test via equivalent public methods, pass an instance of the class under test to the wrapper, and then use reflection from the wrapper class to invoke the private/protected method on the class under test.

编辑:如果您没有使用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 });
       }
    }

#2


4  

I recently had a similar problem and could not find satisfying solution. So I created my own helper function that invokes OnActionExecuted and OnActionExecuting. See code here http://mkramar.blogspot.com.au/2012/06/onactionexecuting-and-onactionexecuted.html

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

#3


0  

I was trying to do this, but I actually wanted to test the outcome of the custom attribute as it applied to the actual controller. In our case we had an authorization attribute that set properties on the controller, the controller then used the properties. Our code looks something like this:

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

// 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

The benefit of this is that we actually execute the custom MVC attribute on the controller we are actually testing. This both exercises the custom attribute code and tests the controller in a situation that is more like the "real world".

这样做的好处是我们实际上在我们实际测试的控制器上执行自定义MVC属性。这两者都练习自定义属性代码并在更像“真实世界”的情况下测试控制器。