2013-03-14 53 views
5

我对.NET Web Api没有太多经验,但是我现在已经使用了它一段时间了,遵循John Papa的关于Pluralsight的SPA应用程序教程。应用程序工作正常,但我现在正在努力的事情是单元测试POST控制器。单元测试后控制器.NET Web Api

我遵循这个令人难以置信的指南如何单元测试网页API控制器。对我来说唯一的问题是测试POST方法。

我的控制器看起来是这样的:

[ActionName("course")] 
    public HttpResponseMessage Post(Course course) 
    { 
     if (course == null) 
      throw new HttpResponseException(HttpStatusCode.NotAcceptable); 
     try 
     { 
      Uow.Courses.Add(course); 
      Uow.commit(); 
     } 
     catch (Exception) 
     { 
      throw new HttpResponseException(HttpStatusCode.InternalServerError); 
     } 

     var response = Request.CreateResponse(HttpStatusCode.Created, course); 

     string uri = Url.Link(routeName: "ControllerActionAndId", 
     routeValues: new { id = course.Id }); 

     response.Headers.Location = new Uri(uri); 

     return response; 
    } 

而且我的单元测试是这样的:

[Test] 
    public void PostShouldReturnHttpResponse() 
    { 
     var populatedPostController = new CoursesController(new TestUOW()); 

     SetupPostControllerForTest(populatedPostController); 

     var course = new Course 
     { 
      Id = 12, 
      Author = new UserProfile() 
      { 
       Firstname = "John", 
       Lastname = "Johnson", 
      }, 
      Description = "Testcourse", 
      Title = "Test Title" 
     }; 

      var responses = populatedPostController.Post(course); 

      ObjectContent content = responses.Content as ObjectContent; 
      Course result = (Course)content.Value; 
      Assert.AreSame(result, course); 
    } 

通过帮助功能:

public static void SetupPostControllerForTest(ApiController controller) 
    { 

     var config = new HttpConfiguration(); 
     var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/courses/course"); 
     var route = config.Routes.MapHttpRoute(
      name: "ControllerActionAndId", 
      routeTemplate: "api/{controller}/{action}/{id}", 
      defaults: null, 
      constraints: new { id = @"^\d+$" } 
     ); 

     var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", "courses" }, { "action", "course" } }); 

     controller.ControllerContext = new HttpControllerContext(config, routeData, request); 
     controller.Request = request; 
     controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config; 
    } 

当我调试单元测试,它似乎失败:

 string uri = Url.Link(routeName: "ControllerActionAndId", 
     routeValues: new { id = course.Id }); 

     response.Headers.Location = new Uri(uri); //Exception because uri = null 

看起来像Url.Link无法找到路线。

我试过this指导,但我真的想要我上面的例子工作。

我在这里错过了一些非常基本的东西吗?

+1

试着在你的'SetupPostControllerForTest'方法'controller.Request.Properties [HttpPropertyKeys.HttpRouteDataKey] = routeData;' – nemesv 2013-03-14 13:46:50

+0

的末尾添加下面这行:是的,它现在可以工作了!这就是当你累了会发生什么..谢谢! – 2013-03-14 14:20:54

回答

4

是的,你错过Nemesv提到的配置中的一行。

controller.Request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData 

正如你所看到的,配置控制器只是为了使用UrlHelper是非常复杂的。出于这个原因,我倾向于避免在控制器类中使用UrlHelper。我通常会引入一个外部依赖关系,使测试更容易,就像IUrlHelper一样,它允许我在单元测试中模拟行为。

public interface IUrlHelper 
    { 
     string Link(string routeName, object routeValues); 
     string Route(string routeName, object routeValues); 
    } 

    public class UrlHelperWrapper : IUrlHelper 
    { 
     UrlHelper helper; 

     public UrlHelperWrapper(UrlHelper helper) 
     { 
      this.helper = helper; 
     } 

     public string Link(string routeName, object routeValues) 
     { 
      return this.helper.Link(routeName, routeValues); 
     } 

     public string Route(string routeName, object routeValues) 
     { 
      return this.helper.Route(routeName, routeValues); 
     } 
    } 

我注入这UrlHelperWraper真正的Web API中,并在测试IUrlHelper接口的模拟。通过这样做,您不需要所有复杂的配置与路线。

Regards, Pablo。

+0

哇。我怎么会错过这个:/。看起来像一个更清洁的方式来处理UrlHelper。很好,谢谢! – 2013-03-14 14:20:02

+0

您好@Pablo Cibraro您能否给我一些现场示例,我正在为我的web api第一次编写我的单元测试,并以我在这里登陆的最优化的方式创建它们。 我不明白你是如何利用URL助手以及你使用URl Helpers消除了哪些问题。任何帮助将不胜感激 – 2014-09-28 14:04:47