2009-02-26 17 views
10

He reemplazado el método OnActionExecuting de mi controlador para establecer un estado interno basado en la ejecución de filterContext. ¿Cómo pruebo esto? El método en sí está protegido, así que supongo que tendré que ir más arriba en la pila de llamadas.¿Cómo pruebo el método OnActionExecuting de mi controlador asp.net-mvc?

¿Qué código necesito para probar esto?

estoy usando MVC RC 1.

Editar: También estoy usando nunit.

Gracias

Respuesta

15

es necesario agregar y utilizar un descriptor de acceso privado. Haga clic con el botón derecho en su clase de controlador y seleccione Create Private Accessors en el menú y agréguelas a su proyecto de prueba. Una vez que esté en su proyecto de prueba, cree su controlador y luego cree un acceso para él. El método debe estar disponible en el descriptor de acceso. Aquí está una prueba de muestra de mi propio código:

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

} 

EDITAR: Si no está utilizando MSTest para sus pruebas de unidad, puede que tenga que generar los descriptores de acceso con la mano. Básicamente, usted hace una clase contenedora que expone los métodos privados/protegidos de la clase bajo prueba a través de métodos públicos equivalentes, pasa una instancia de la clase bajo prueba a la envoltura y luego usa la reflexión de la clase contenedora para invocar a los privados/protegidos método en la clase bajo prueba.

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

¿Es esto MSTest específico? Estoy usando nunit y xunit atm. –

+0

Solo pregunto porque no veo el botón de contexto 'Agregar acceso' y hacer una búsqueda en Google me lleva a probar algo específico. –

+0

Sí, creo que sí. Supongo que requiere al menos VS Pro para que esté allí. Sin embargo, puede crear uno a mano y usar la reflexión para invocar el método apropiado en el objeto privado subyacente. – tvanfosson

4

Recientemente tuve un problema similar y no pude encontrar una solución satisfactoria. Así que creé mi propia función auxiliar que invoca OnActionExecuted y OnActionExecuting. Ver código aquí http://mkramar.blogspot.com.au/2012/06/onactionexecuting-and-onactionexecuted.html

+0

Observe cómo la respuesta aceptada incluye * código y explicación *, y carece de enlaces auto-promocionales? Ese es el patrón de respuestas aceptables aquí. –

+0

No conseguí que el otro trabajara. Pero tu código funciona. Tal vez debería editar tu respuesta y agregar tu código. Combiné tu código con http://stackoverflow.com/a/10316899/648076. Ahora la prueba se ve muy bien. –

0

yo estaba tratando de hacer esto, pero en realidad quería prueba el resultado del atributo personalizado ya que se aplica a la controlador real. En nuestro caso, teníamos un atributo de autorización que establecía propiedades en el controlador, luego el controlador usaba las propiedades. Nuestro código es como la siguiente:

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

El beneficio de esto es que realmente ejecutan el atributo MVC personalizado en el controlador en realidad estamos probando. Esto ejerce el código de atributo personalizado y prueba el controlador en una situación que se parece más al "mundo real".

+0

Simplemente una pregunta rápida 2 años después del hecho: ¿cómo se establece una propiedad de controlador a través de un atributo derivado? – VisualBean

Cuestiones relacionadas