2009-03-23 14 views
164

Una de mis acciones de controladores, una que se llama en una solicitud Ajax, devuelve una URL al lado del cliente para que pueda hacer una redirección. Estoy usando Url.RouteUrl(..) y durante mis pruebas de la unidad esto falla ya que el parámetro Controller.Url no se llena previamente.ASP.NET MVC: Controladores de pruebas unitarias que usan UrlHelper

He intentado muchas cosas, entre otras que tratan de código auxiliar UrlHelper (que no), la creación manual de un UrlHelper con un RequestContext que tiene un stubbed HttpContextBase (que no está en una llamada RouteCollection.GetUrlWithApplicationPath).

He buscado en Google pero no he encontrado prácticamente nada sobre el tema. ¿Estoy haciendo algo increíblemente estúpido usando Url.RouteUrl en mi acción de controlador? hay una manera mas facil?

Para empeorar las cosas, me gustaría poder probar la URL devuelta en mi prueba de unidad; de hecho, solo estoy interesado en saber que está redireccionando a la ruta correcta, pero dado que estoy devolviendo un URL en lugar de una ruta, me gustaría controlar la URL que se resuelve (por ejemplo, utilizando un stubbed RouteCollection), pero me alegrará obtener mi prueba de aprobación para comenzar.

Respuesta

196

He aquí una de mis pruebas (xUnit + MOQ) sólo para caso similar (usando Url.RouteUrl en el controlador)

espero que esto ayude:

var routes = new RouteCollection(); 
MvcApplication.RegisterRoutes(routes); 

var request = new Mock<HttpRequestBase>(MockBehavior.Strict); 
request.SetupGet(x => x.ApplicationPath).Returns("/"); 
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute)); 
request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection()); 

var response = new Mock<HttpResponseBase>(MockBehavior.Strict); 
response.Setup(x => x.ApplyAppPathModifier("/post1")).Returns("http://localhost/post1"); 

var context = new Mock<HttpContextBase>(MockBehavior.Strict); 
context.SetupGet(x => x.Request).Returns(request.Object); 
context.SetupGet(x => x.Response).Returns(response.Object); 

var controller = new LinkbackController(dbF.Object); 
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller); 
controller.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes); 
+2

Por el momento me fui con una solución en la que abstrae las llamadas a UrlHelper para que pueda interceptarlos. Gracias por su fragmento, sin embargo, me ahorrará mucho tiempo tratando de encontrar una manera correcta de burlar un Request/Response/ControllerContext. – efdee

+0

Gracias por la respuesta @ eu-ge-ne, me ayudó mucho también. He incluido algunas configuraciones moq más para usar un parámetro formcollection utilizado por UpdateModel – woopstash

+16

+1 excelente. Aunque un consejo: lo utilizo como un MockHelper y cambio la respuesta. Configuro para ApplyAppPathModifier a esto: response.Setup (x => x.ApplyAppPathModifier (Moq.It.IsAny ())).Devuelve ((String url) => url); Es feo, pero recupero el objeto serializado en formato de url codificado, en lugar de codificar el valor devuelto. – eduncan911

12

Este puesto puede ser útil si se desea para burlarse de la clase HttpContextBase.

http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx

+0

Genial, esto me ayudó, aunque tuve que agregar un código adicional al método FakeHttpContext para detener el estallido del asistente: context.Setup (ctx => ctx.Request.ApplicationPath) .Returns ("/ AntiBlowup "); También refactoré el código para que use la sintaxis más reciente de Setup(). Gracias. – RichardOD

2

La construcción de la respuesta por @ eu-ge-ne que me ha ayudado mucho:

tuve una ActionResult que hizo una redirección, así como había una llamada UpdateModel con un parámetro FormCollection . Para el UpdateModel() para trabajar he tenido que añadir esto a mi HttpRequestBase burlado:

FormCollection collection = new FormCollection(); 
collection["KeyName"] = "KeyValue"; 

request.Setup(x => x.Form).Returns(collection); 
request.Setup(x => x.QueryString).Returns(new NameValueCollection()); 

Para probar que la URL redirigida era correcta, puede hacer lo siguiente:

RedirectResult result = controller.ActionName(modelToSubmit, collection) as RedirectResult; 
Assert.AreEqual("/Expected/URL", result.Url); 
33

Una implementación modificada de eu-ge-ne. Éste devuelve un enlace generado en función de las rutas definidas en la aplicación. El ejemplo de eu-ge-ne siempre devuelve una respuesta fija. El siguiente enfoque le permitirá probar que la acción correcta/controlador y la información de ruta se transfieren al UrlHelper, que es lo que desea si está probando la llamada al UrlHelper.

var context = new Mock<HttpContextBase>(); 
var request = new Mock<HttpRequestBase>(); 
var response = new Mock<HttpResponseBase>(); 
var session = new Mock<HttpSessionStateBase>(); 
var server = new Mock<HttpServerUtilityBase>(); 

context.Setup(ctx => ctx.Request).Returns(request.Object); 
context.Setup(ctx => ctx.Response).Returns(response.Object); 
context.Setup(ctx => ctx.Session).Returns(session.Object); 
context.Setup(ctx => ctx.Server).Returns(server.Object); 

request.SetupGet(x => x.ApplicationPath).Returns("/"); 
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute)); 
request.SetupGet(x => x.ServerVariables).Returns(new NameValueCollection()); 

response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(x => x); 

context.SetupGet(x => x.Request).Returns(request.Object); 
context.SetupGet(x => x.Response).Returns(response.Object); 

var routes = new RouteCollection(); 
MvcApplication.RegisterRoutes(routes); 
var helper = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes); 
+0

¡Respuesta perfecta para mí, gracias Steven! – jhilden

Cuestiones relacionadas