asp.net-mvc - test - pruebas unitarias mvc 5
Mocking Asp.net-mvc Contexto del controlador (7)
Entonces el contexto del controlador depende de algunos internos 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".
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 rhino mocks
Aquí hay un fragmento del enlace de Jason. Es lo mismo que el método de Phil pero usa rhino.
Nota: mockHttpContext.Request se repite para devolver mockRequest antes de que las partes internas de mockRequest se anulen. 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
...
Aquí hay una clase de prueba de unidad de muestra que usa 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 valor de la solicitud y establece el encabezado http en los objetos de respuesta. Otros objetos de contexto http podrían burlarse 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);
}
}
El procedimiento para esto 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 burlas 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);
Me parece que ese largo procedimiento de burla es demasiada 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í hay un example
O puede hacer esto con Typemock Isolator sin necesidad de enviar un controlador falso en absoluto:
Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get");
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 de Rhino Mocks es similar.
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 está 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