2009-02-26 23 views

risposta

15

È necessario aggiungere e utilizzare una funzione di accesso privato. Fai clic con il tasto destro del mouse sulla classe controller e scegli Create Private Accessors dal menu e aggiungili al tuo progetto di test. Una volta nel progetto di test, crea il controller, quindi crea un accesso per esso. Il metodo dovrebbe essere disponibile sull'accessorio. Ecco un test di esempio dal mio codice:

/// <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: Se non siete usando MSTest per il test di unità, potrebbe essere necessario generare le funzioni di accesso a mano. In sostanza, si crea una classe wrapper che espone i metodi privati ​​/ protetti della classe sotto test tramite metodi pubblici equivalenti, passa un'istanza della classe sotto test al wrapper e quindi usa reflection dalla classe wrapper per richiamare il private/protected metodo sulla classe sotto test.

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

Questo MSTest è specifico? Sto usando nunit e xunit atm. –

+0

Chiedo solo perché non vedo il pulsante di contesto "aggiungi Accessor" e facendo una ricerca su Google mi porta in alcuni test di MS materiale specifico. –

+0

Sì, penso che lo sia. Suppongo che sia necessario almeno VS Pro perché sia ​​lì. Puoi comunque crearne uno a mano e usare reflection per invocare il metodo appropriato sull'oggetto privato sottostante. – tvanfosson

4

Recentemente ho avuto un problema simile e non sono riuscito a trovare una soluzione soddisfacente. Così ho creato la mia propria funzione di supporto che richiama OnActionExecuted e OnActionExecuting. Vedere il codice qui http://mkramar.blogspot.com.au/2012/06/onactionexecuting-and-onactionexecuted.html

+0

Nota come la risposta accettata include * codice e spiegazione * e manca di link autopromozionali? Questo è lo schema per le risposte accettabili qui. –

+0

Non ho avuto l'altro a lavorare. Ma il tuo codice funziona. Forse dovrei modificare la tua risposta e aggiungere il tuo codice. Ho combinato il tuo codice con http://stackoverflow.com/a/10316899/648076. Ora il test sembra davvero bello. –

0

stavo cercando di fare questo, ma io in realtà volevo prova l'esito della attributo personalizzato in quanto applicato al controller attuale. Nel nostro caso disponevamo di un attributo di autorizzazione che impostava le proprietà sul controller, quindi il controller utilizzava le proprietà. Il nostro codice simile a questa:

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

Il vantaggio di questo è che abbiamo effettivamente eseguiamo l'attributo MVC personalizzato sul controller in realtà stiamo testando. Questo esercita il codice dell'attributo personalizzato e verifica il controller in una situazione che è più simile al "mondo reale".

+0

Solo una breve domanda 2 anni dopo il fatto - come si imposta una proprietà del controllore attraverso un attributo derivato? – VisualBean

Problemi correlati