2010-06-18 10 views
5

Tengo dificultades para probar los controladores. Original de mi regulador para la prueba parecía algo como esto:asp.net mvc Cómo probar los controladores correctamente

SomethingController CreateSomethingController() 
{ 
    var somethingData = FakeSomethingData.CreateFakeData(); 
    var fakeRepository = FakeRepository.Create(); 

    var controller = new SomethingController(fakeRepository); 

    return controller; 
} 

Esto funciona bien para la mayoría de las pruebas hasta que llegué a la parte Request.IsAjaxRequest() de código. Entonces tuve que burlarme de HttpContext y HttpRequestBase. Así que mi código a continuación, cambió para parecerse a:

public class FakeHttpContext : HttpContextBase 
{ 
    bool _isAjaxRequest; 

    public FakeHttpContext(bool isAjaxRequest = false) 
    { 
     _isAjaxRequest = isAjaxRequest; 
    } 

    public override HttpRequestBase Request 
    { 
     get 
     { 
      string ajaxRequestHeader = ""; 

      if (_isAjaxRequest) 
       ajaxRequestHeader = "XMLHttpRequest"; 

      var request = new Mock<HttpRequestBase>(); 
      request.SetupGet(x => x.Headers).Returns(new WebHeaderCollection 
      { 
       {"X-Requested-With", ajaxRequestHeader} 
      }); 

      request.SetupGet(x => x["X-Requested-With"]).Returns(ajaxRequestHeader); 

      return request.Object; 
     } 
    } 

    private IPrincipal _user; 

    public override IPrincipal User 
    { 
     get 
     { 
      if (_user == null) 
      { 
       _user = new FakePrincipal(); 
      } 
      return _user; 
     } 
     set 
     { 
      _user = value; 
     } 
    } 
} 


SomethingController CreateSomethingController() 
{ 
    var somethingData = FakeSomethingData.CreateFakeData(); 
    var fakeRepository = FakeRepository.Create(); 

    var controller = new SomethingController(fakeRepository); 

    ControllerContext controllerContext = new ControllerContext(new FakeHttpContext(isAjaxRequest), new RouteData(), controller); 
    controller.ControllerContext = controllerContext; 

    return controller; 
} 

ahora su conseguido a esa etapa de mi controlador donde llamo Url.Route y Url es nulo. Entonces parece que necesito comenzar a burlar las rutas de mi controlador.

Parece que paso más tiempo buscando en Google cómo falsificar/simular objetos y luego depurar para asegurarme de que mis falsificaciones son correctas en lugar de escribir el código de prueba. ¿Hay una manera más fácil de probar un controlador? Miré el TestControllerBuilder desde MvcContrib, que ayuda con algunos de los problemas pero parece que no hace todo. ¿Hay algo más disponible que haga el trabajo y me permita concentrarme en escribir las pruebas en lugar de escribir burlas?

Gracias

+1

El problema no es con sus pruebas, es con la acción de su controlador. Debe intentar evitar el uso del contexto http en su acción y solo usar las dependencias que suministre en su constructor. Las acciones deben ser muy pequeñas. –

Respuesta

1

Se pueden utilizar algunas de las bibliotecas que le dan fuera de la caja algunos de estos objetos. Por ejemplo RhinoMock, NMock ... etc. Yo personalmente uso Moq - es lo suficientemente bueno y gratis. Lo que más me gusta de Moq son las expresiones linq.

1

La mayor parte del motor de burla hará todo esto por usted. Yo uso RhinoMocks pero hay mucho más disponible. También Moles es un motor de burla muy nuevo e interesante (esto generalmente viene con Pex, que es aún más munición en su unidad de arsenal de prueba)

1

MvcContrib + RhinoMocks. Consulte el TestControllerBuilder en la biblioteca MvcContrib.TestHelper. Aquí está el informe oficial: http://mvccontrib.codeplex.com/wikipage?title=TestHelper#Examples.

He aquí un ejemplo de burlarse de un controlador a cabo para probar una UrlHelper: ASP.NET MVC: Mock controller.Url.Action

He aquí una breve explicación de cómo utilizar el TestControllerBuilder: http://codebetter.com/blogs/kyle.baley/archive/2008/03/19/testcontrollerbuilder-in-mvccontrib.aspx

1

En lugar de burlarse de las cosas, se puede pasar IAjaxRequest al constructor. O haga que sea la propiedad de clase de constructor base (y use la inyección de propiedad). O puede hacer que su constructor implemente IAjaxRequest y luego aplique el filtro de acción global en la clase de constructor base que configurará IAjaxRequest.

Esto ayudará a abstraer muchas cosas, incluyendo cosas de HttpContext. Simplemente no abstraiga IHttpContext, abstract IUserContext, ISessionStorage, IAuthentication, IRequestDetails ...

Otra forma es usar el modelo de carpeta directamente en los métodos donde necesita información específica. Ver this post por ejemplo. Puedes hacer un encuadernador que te dará IsAjaxRequest, luego solo debes hacer algo para aceptar este parámetro. Funciona muy bien porque la información se proporciona exactamente al método que la necesita, no a todo el controlador.

Cuestiones relacionadas