2009-02-26 19 views

Odpowiedz

15

Musisz dodać i używać prywatnego dostępu. Kliknij prawym przyciskiem myszy klasę kontrolera i wybierz z menu opcję Create Private Accessors i dodaj je do swojego projektu testowego. Po przejściu do projektu testowego utwórz kontroler, a następnie utwórz dla niego akcesorium. Metoda powinna być dostępna na akcesorze. Oto przykładowy test z własnego kodu:

/// <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: Jeśli nie jesteś przy użyciu MSTest dla testów jednostkowych, być może trzeba będzie generować akcesorów ręcznie. Zasadniczo tworzysz klasę opakowania, która ujawnia prywatne/chronione metody badanej klasy za pomocą równoważnych publicznych metod, przekazuje instancję testowanej klasy do opakowania, a następnie używa refleksji z klasy opakowania, aby wywołać prywatne/chronione metoda na testowanej klasie.

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

Czy ten MST jest konkretny? Używam atmów nunit i xunit. –

+0

Pytam tylko dlatego, że nie widzę przycisku kontekstowego "dodawaj elementu dodającego", a wyszukiwanie w Google przynosi mi pewne testy specyficzne dla ms. –

+0

Tak, myślę, że tak. Przypuszczam, że wymaga to przynajmniej wersji VS Pro, aby ją tam było. Możesz jednak utworzyć je ręcznie i użyć odbicia, aby wywołać odpowiednią metodę na bazowym obiekcie prywatnym. – tvanfosson

4

Niedawno miałem podobny problem i nie mogłem znaleźć satysfakcjonującego rozwiązania. Stworzyłem więc własną funkcję pomocniczą, która wywołuje procedury OnActionExecuted i OnActionExecuting. Zobacz kod tutaj http://mkramar.blogspot.com.au/2012/06/onactionexecuting-and-onactionexecuted.html

+0

Zwróć uwagę, że zaakceptowana odpowiedź zawiera * kod i objaśnienie *, a także brak linków autopromocyjnych? Oto wzór akceptowalnych odpowiedzi tutaj. –

+0

Nie dostałem drugiego do pracy. Ale twój kod działa. Może powinienem edytować twoje odpowiedzi i dodać twój kod. Połączyłem Twój kod z http://stackoverflow.com/a/10316899/648076. Teraz test wygląda naprawdę przyjemnie. –

0

starałem się to zrobić, ale rzeczywiście chciał teście wynik zwyczaju przypisywać gdyż zastosowane do rzeczywistego kontrolera. W naszym przypadku mieliśmy atrybut autoryzacji, który ustawiał właściwości na kontrolerze, kontroler następnie używał właściwości. Nasz kod wygląda mniej więcej tak:

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

Korzyść z tego jest to, że rzeczywiście możemy wykonać niestandardowy atrybut MVC na kontrolerze jesteśmy faktycznie testowania. Oba testują niestandardowy kod atrybutu i testują kontroler w sytuacji bardziej przypominającej "rzeczywisty świat".

+0

Po prostu krótkie pytanie 2 lata po fakcie - w jaki sposób można ustawić właściwość kontrolera za pomocą atrybutu pochodnego? – VisualBean

Powiązane problemy