6

我对 .NET Web Api 没有太多经验,但我已经使用它一段时间了,遵循 John Papa 在 Pluralsight 上的 SPA 应用程序教程。该应用程序运行良好,但我现在正在努力解决的问题是对 POST 控制器进行单元测试。

我已经按照这个令人难以置信的指南来了解如何对 web 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 找不到路线。

我也尝试了本指南,但我真的希望上面的示例能够正常工作。

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

4

1 回答 1

5

是的,您缺少 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 接口。通过这样做,您不需要对路由进行所有复杂的配置。

问候,巴勃罗。

于 2013-03-14T14:04:09.420 回答