2008-08-28 26 views
62

Por lo tanto, el contexto del controlador depende de algunas partes internas de asp.net. ¿Cuáles son algunas formas de simular estas pruebas para pruebas unitarias? Parece que es muy fácil bloquear pruebas con toneladas de configuración cuando solo necesito, por ejemplo, Request.HttpMethod para devolver "GET".Contexto del controlador Asp.net-mvc burlón

He visto algunos ejemplos/ayudantes en las redes, pero algunos tienen fecha. Pensé que este sería un buen lugar para mantener lo último y mejor.

estoy usando la última versión de burla de Rhino

+0

Estaba considerando hacer esto. Pero solo necesitaba el simulacro para la conexión de la base de datos. En lugar de probar la asignación de la base de datos, moví la función a una clase regular y probé esa función, sin conexión a la base de datos. – MrFox

Respuesta

58

Usando MoQ se ve algo como esto:

var request = new Mock<HttpRequestBase>(); 
request.Expect(r => r.HttpMethod).Returns("GET"); 
var mockHttpContext = new Mock<HttpContextBase>(); 
mockHttpContext.Expect(c => c.Request).Returns(request.Object); 
var controllerContext = new ControllerContext(mockHttpContext.Object 
, new RouteData(), new Mock<ControllerBase>().Object); 

creo que la sintaxis burla de Rhino es similar.

+16

Esto ya no es válido en MVC3. Al pasar en un RouteData vacío, se lanzarán excepciones cuando se llame al método GetRequiredString no virtual y no destructivo en RouteData. – ScottKoon

+2

@ScottKoon Sírvanse proporcionar una demostración de lo que debe ser similar – Jon

+1

La respuesta a esta pregunta se muestra cómo burlarse de la RouteData. http://stackoverflow.com/questions/986183/mocking-the-routedata-class-in-system-web-routing-for-mvc-applications – ScottKoon

1

Me parece que el procedimiento de burla largo es demasiado fricción.

La mejor manera que hemos encontrado, utilizando ASP.NET MVC en un proyecto real, es abstraer el HttpContext a una interfaz IWebContext que simplemente se transfiere. Entonces puedes burlarte del IWebContext sin ningún problema.

Aquí es un example

+1

¿Puedes explicar esto un poco más? – user40097

17

He aquí un fragmento de enlace de Jason. Es lo mismo que el método de Phil pero usa rhino.

Nota: mockHttpContext.Request se apagó para volver mockRequest antes internos de mockRequest se apagaron. Creo que esta orden es obligatoria.

// create a fake web context 
var mockHttpContext = MockRepository.GenerateMock<HttpContextBase>(); 
var mockRequest = MockRepository.GenerateMock<HttpRequestBase>(); 
mockHttpContext.Stub(x => x.Request).Return(mockRequest); 

// tell the mock to return "GET" when HttpMethod is called 
mockRequest.Stub(x => x.HttpMethod).Return("GET");    

var controller = new AccountController(); 

// assign the fake context 
var context = new ControllerContext(mockHttpContext, 
        new RouteData(), 
        controller); 
controller.ControllerContext = context; 

// act 
... 
2

he terminado con esta especificación

public abstract class Specification <C> where C: Controller 
{ 
    protected C controller; 

    HttpContextBase mockHttpContext; 
    HttpRequestBase mockRequest; 

    protected Exception ExceptionThrown { get; private set; } 

    [SetUp] 
    public void Setup() 
    { 
     mockHttpContext = MockRepository.GenerateMock<HttpContextBase>(); 
     mockRequest = MockRepository.GenerateMock<HttpRequestBase>(); 

     mockHttpContext.Stub(x => x.Request).Return(mockRequest); 
     mockRequest.Stub(x => x.HttpMethod).Return("GET"); 


     EstablishContext(); 
     SetHttpContext(); 

     try 
     { 
      When(); 
     } 
     catch (Exception exc) 
     { 
      ExceptionThrown = exc; 
     } 
    } 

    protected void SetHttpContext() 
    { 
     var context = new ControllerContext(mockHttpContext, new RouteData(), controller); 
     controller.ControllerContext = context; 
    } 

    protected T Mock<T>() where T: class 
    { 
     return MockRepository.GenerateMock<T>(); 
    } 

    protected abstract void EstablishContext(); 
    protected abstract void When(); 

    [TearDown] 
    public virtual void TearDown() 
    { 
    } 
} 

y el jugo es aquí

[TestFixture] 
public class When_invoking_ManageUsersControllers_Update :Specification <ManageUsersController> 
{ 
    private IUserRepository userRepository; 
    FormCollection form; 

    ActionResult result; 
    User retUser; 

    protected override void EstablishContext() 
    { 
     userRepository = Mock<IUserRepository>(); 
     controller = new ManageUsersController(userRepository); 

     retUser = new User(); 
     userRepository.Expect(x => x.GetById(5)).Return(retUser); 
     userRepository.Expect(x => x.Update(retUser)); 

     form = new FormCollection(); 
     form["IdUser"] = 5.ToString(); 
     form["Name"] = 5.ToString(); 
     form["Surename"] = 5.ToString(); 
     form["Login"] = 5.ToString(); 
     form["Password"] = 5.ToString(); 
    } 

    protected override void When() 
    { 
     result = controller.Edit(5, form); 
    } 

    [Test] 
    public void is_retrieved_before_update_original_user() 
    { 
     userRepository.AssertWasCalled(x => x.GetById(5)); 
     userRepository.AssertWasCalled(x => x.Update(retUser)); 
    } 
} 

disfrutar

7

o se puede hacer esto con Typemock aislador sin necesidad para enviar un controlador falso:

Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get"); 
9

El procedimiento para esta parece haber cambiado ligeramente en MVC2 (estoy usando RC1). La solución de Phil Haack no funciona para mí si la acción requiere un método específico ([HttpPost], [HttpGet]). Especulando en Reflector, parece que el método para verificar estos atributos ha cambiado. MVC ahora comprueba request.Headers, request.Form y request.QueryString para un valor de X-HTTP-Method-Override.

Si agrega burla para estas propiedades, funciona:

var request = new Mock<HttpRequestBase>(); 
request.Setup(r => r.HttpMethod).Returns("POST"); 
request.Setup(r => r.Headers).Returns(new NameValueCollection()); 
request.Setup(r => r.Form).Returns(new NameValueCollection()); 
request.Setup(r => r.QueryString).Returns(new NameValueCollection()); 

var mockHttpContext = new Mock<HttpContextBase>(); 
mockHttpContext.Expect(c => c.Request).Returns(request.Object); 
var controllerContext = new ControllerContext(mockHttpContext.Object, new RouteData(), new Mock<ControllerBase>().Object); 
+1

Esto funcionó para mí, sin embargo, en MVC2 RC también tuve que agregar lo siguiente: request.Setup (r => r.Files) .Returns (. Mock nueva () del objeto); de lo contrario, obtengo una excepción nullreference –

19

Aquí es una clase de prueba unidad de muestra usando MSTEST y Moq que se burla de los objetos HttpRequest y HttpResponse. (.NET 4.0, ASP.NET MVC 3.0)

La acción del controlador obtiene el valor de la solicitud y establece el encabezado http en los objetos de respuesta.Otros objetos de contexto HTTP podrían ser burlados de manera similar

[TestClass] 
public class MyControllerTest 
{ 
    protected Mock<HttpContextBase> HttpContextBaseMock; 
    protected Mock<HttpRequestBase> HttpRequestMock; 
    protected Mock<HttpResponseBase> HttpResponseMock; 

    [TestInitialize] 
    public void TestInitialize() 
    { 
     HttpContextBaseMock = new Mock<HttpContextBase>(); 
     HttpRequestMock = new Mock<HttpRequestBase>(); 
     HttpResponseMock = new Mock<HttpResponseBase>(); 
     HttpContextBaseMock.SetupGet(x => x.Request).Returns(HttpRequestMock.Object); 
     HttpContextBaseMock.SetupGet(x => x.Response).Returns(HttpResponseMock.Object); 
    } 

    protected MyController SetupController() 
    { 
     var routes = new RouteCollection(); 
     var controller = new MyController(); 
     controller.ControllerContext = new ControllerContext(HttpContextBaseMock.Object, new RouteData(), controller); 
     controller.Url = new UrlHelper(new RequestContext(HttpContextBaseMock.Object, new RouteData()), routes); 
     return controller; 
    } 

    [TestMethod] 
    public void IndexTest() 
    { 
     HttpRequestMock.Setup(x => x["x"]).Returns("1"); 
     HttpResponseMock.Setup(x => x.AddHeader("name", "value")); 

     var controller = SetupController(); 
     var result = controller.Index(); 
     Assert.AreEqual("1", result.Content); 

     HttpRequestMock.VerifyAll(); 
     HttpResponseMock.VerifyAll(); 
    } 
} 

public class MyController : Controller 
{ 
    public ContentResult Index() 
    { 
     var x = Request["x"]; 
     Response.AddHeader("name", "value"); 
     return Content(x); 
    } 
} 
+0

¡Muchas, muchas gracias! Me ayudó mucho. Desearía poder votarlo diez veces. –

+0

@Maksym Kozlenko Muchas, muchas gracias. Esto me ayudó mucho –

Cuestiones relacionadas