2012-08-02 29 views
10

Tengo el siguiente acción del controladorcontrolador WebAPI Prueba Url.Link

public void Post(Dto model) 
{ 
    using (var message = new MailMessage()) 
    { 
     var link = Url.Link("ConfirmAccount", new { model.Id }); 

     message.To.Add(model.ToAddress); 
     message.IsBodyHtml = true; 
     message.Body = string.Format(@"<p>Click <a href=""{0}"">here</a> to complete your registration.<p><p>You may also copy and paste this link into your browser.</p><p>{0}</p>", link); 

     MailClient.Send(message); 
    } 
} 

Para probar esto necesito para configurar el controlador de contexto

var httpConfiguration = new HttpConfiguration(new HttpRouteCollection { { "ConfirmAccount", new HttpRoute() } }); 
var httpRouteData = new HttpRouteData(httpConfiguration.Routes.First()); 
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "http://localhost"); 
sut = new TheController 
{ 
    ControllerContext = new HttpControllerContext(httpConfiguration, httpRouteData, httpRequestMessage), 
    MailClient = new SmtpClient { PickupDirectoryLocation = location } 
}; 

Esto parece como un montón de configuración para probar la creación de un enlace. ¿Hay una manera más limpia de hacer esto? He leído acerca de los servidores en memoria, pero parece que se aplica más al httpclient que al controlador directamente.

+0

+1 Pensé que el objetivo de los servicios REST era permitir recursos enlazables. Realmente no estoy contento con las utilidades WebAPI Link/Url. Hacer referencia al nombre de la ruta parece tan frágil y la historia de prueba es igualmente dolorosa. Afortunadamente, hay algunas mejoras por venir ... –

Respuesta

2

Me encuentro con la misma estupidez. Todas las referencias que puedo encontrar le piden que se burle de la Solicitud/Controlador, que es (como usted señaló) un montón de trabajo.

referencias específicas:

No he intentado probar los frameworks de Mocking, así que tengo una clase de ayuda para "construir" mi controlador. Así que en lugar de

sut = new TheController { ... } 

utilizo algo como:

// actually rolled together to `sut = MyTestSetup.GetController(method, url)` 
sut = new TheController()... 
MyTestSetup.FakeRequest(sut, HttpMethod.Whatever, "~/the/expected/url"); 

Como referencia, el método es básicamente:

public void FakeRequest(ApiController controller, HttpMethod method = null, string requestUrl = null, string controllerName = null) { 
    HttpConfiguration config = new HttpConfiguration(); 
    // rebuild the expected request 
    var request = new HttpRequestMessage(null == method ? this.requestMethod : method, string.IsNullOrWhiteSpace(requestUrl) ? this.requestUrl : requestUrl); 
    //var route = System.Web.Routing.RouteTable.Routes["DefaultApi"]; 
    var route = config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}"); 

    // TODO: get from application? maybe like https://stackoverflow.com/a/5943810/1037948 
    var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", string.IsNullOrWhiteSpace(controllerName) ? this.requestController : controllerName } }); 

    controller.ControllerContext = new HttpControllerContext(config, routeData, request); 

    // attach fake request 
    controller.Request = request; 
    controller.Request.Properties[/* "MS_HttpConfiguration" */ HttpPropertyKeys.HttpConfigurationKey] = config; 
} 
+0

Ahora estoy usando [RazorGenerator] (http://razorgenerator.codeplex.com/) para compilar el texto en lugar de construir manualmente los enlaces en el controlador. –

12

A continuación se muestra el código mínimo absoluto requerido para probar UrlHelper sin ningún tipo de la biblioteca burlona. Lo que me arrojó (y me llevó algo de tiempo rastrear) fue que debes establecer el IHttpRouteData de la solicitud. Si no lo hace, la instancia IHttpRoute no generará una ruta virtual que dé como resultado una URL vacía.

public class FooController : ApiController 
    { 
     public string Get() 
     { 
      return Url.Link(RouteNames.DefaultRoute, new { controller = "foo", id = "10" }); 
     } 
    } 

    [TestFixture] 
    public class FooControllerTests 
    { 
     FooController controller; 

     [SetUp] 
     public void SetUp() 
     { 
      var config = new HttpConfiguration(); 

      config.Routes.MapHttpRoute(
       name: "Default", 
       routeTemplate: "api/{controller}/{id}", 
       defaults: new { id = RouteParameter.Optional }); 

      var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost"); 
      request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config; 
      request.Properties[HttpPropertyKeys.HttpRouteDataKey] = new HttpRouteData(new HttpRoute()); 

      controller = new FooController 
      { 
       Request = request 
      }; 
     } 

     [Test] 
     public void Get_returns_link() 
     { 
      Assert.That(controller.Get(), Is.EqualTo("http://localhost/api/foo/10")); 
     } 
    } 
+6

¿Alguna actualización sobre esto desde que salió la aplicación web api2? – GetFuzzy

+0

Tuve que crear también la propiedad 'ControllerContext' de' FooController', incluido su 'ControllerDescriptor'. Heredé este código y no estoy seguro de qué versión de API web estoy usando, pero es MVC 4. –

+0

@GetFuzzy Un poco tarde, pero acabo de descifrar esto y estoy agregando una respuesta. – krillgar

11

Comencé a utilizar este enfoque con Web API 2.0.

Si está utilizando una biblioteca de burlas (y realmente debería hacer pruebas en unidades del mundo real), puede burlarse directamente del objeto UrlHelper ya que todos los métodos que contiene son virtual.

var mock = new Mock<UrlHelper>(); 
mock.Setup(m => m.Link(It.IsAny<string>(), It.IsAny<object>())).Returns("test url"); 

var controller = new FooController { 
    Url = mock.Object 
}; 

Esta es una solución mucho más limpia que la respuesta de Ben Foster, al igual que con ese enfoque, es necesario agregar rutas a la configuración para cada nombre que está utilizando. Eso podría cambiar fácilmente o ser una cantidad ridículamente grande de rutas para configurar.

+0

debería ser la respuesta aceptada. Simple y elegante. Necesitaba este código también. var context = new HttpRequestContext {Url = mockUrlHelper.Object}; request.Properties.Add (HttpPropertyKeys.RequestContextKey, context); – CountZero

+0

@CountZero ¿Qué hizo que necesitaras eso? Si desea agregar eso como su propia respuesta, y construir desde la mía, eso podría ser bueno, o podemos combinarlo aquí. Depende de ti, pero un poco de contexto (sin juego de palabras) sería útil. – krillgar

Cuestiones relacionadas