如何测试我的asp.net-mvc控制器的OnActionExecuting方法?

如何测试我的asp.net-mvc控制器的OnActionExecuting方法?

问题描述:

我重写了我的控制器的OnActionExecuting方法,根据执行的filterContext设置一些内部状态。我如何测试这个?该方法本身是受保护的,所以我认为我必须在调用堆栈中更高。如何测试我的asp.net-mvc控制器的OnActionExecuting方法?

我需要测试什么代码?

我使用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的单元测试,您可能需要手动生成的存取。从本质上讲,你创建一个包装类,它通过等价的公共方法公开被测试类的私有/受保护方法,将被测试类的实例传递给包装,然后使用包装类的反射来调用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 }); 
     } 
    } 
+0

这是MSTest特有的吗?我正在使用nunit和xunit atm。 – 2009-02-26 18:20:43

+0

我只问,因为我没有看到'添加访问器'的上下文按钮,做一个谷歌搜索带给我一些MS测试特定的东西。 – 2009-02-26 18:21:43

+0

是的,我认为是。我认为它至少需要VS Pro才能在那里。您可以手动创建一个,并使用反射来调用底层专用对象上的适当方法。 – tvanfosson 2009-02-26 19:36:52

我最近有一个类似的问题,找不到满意的解决方案。所以我创建了自己的帮助函数,它调用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。这既执行自定义属性代码,又在更像“真实世界”的情况下测试控制器。