使用 Request.CreateResponse 进行 ASP.NET WebApi 单元测试

Posted

技术标签:

【中文标题】使用 Request.CreateResponse 进行 ASP.NET WebApi 单元测试【英文标题】:ASP.NET WebApi unit testing with Request.CreateResponse 【发布时间】:2012-06-07 18:44:00 【问题描述】:

我正在尝试为我的 ApiController 编写一些单元测试,但遇到了一些问题。有一个很好的扩展方法,叫做 Request.CreateResponse,它对生成响应有很大帮助。

public HttpResponseMessage Post(Product product)

  var createdProduct = repo.Add(product);
  return this.Request.CreateResponse(HttpStatusCode.Created, createdProduct);

有没有办法在不使用部分模拟或直接使用“new HttpResponseMessage(...)”的情况下模拟 CreateResponse?

【问题讨论】:

为什么要模拟CreateResponse?为什么不对返回的 HttpResponseMessage ContentStatusCode 属性断言设置了正确的值? 如果我以单元测试的形式运行此方法,它将失败,但未设置配置。 好吧,真丢人,我只需要写 this.Request.CreateResponse(HttpStatusCode.Accepted, createdProduct, GlobalConfiguration.Configuration) 【参考方案1】:

解决此问题的另一种方法是执行以下操作:

controller.Request = new HttpRequestMessage();
controller.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, 
                                  new HttpConfiguration());

如果您要升级到 webapi 5.0,则需要将其更改为:

controller.Request = new HttpRequestMessage();
controller.Request.SetConfiguration(new HttpConfiguration());

您需要这样做的原因是因为您必须在控制器上填充Request,否则Request 上的扩展方法将不起作用。您还必须在请求上设置HttpConfiguration,否则路由和管道的其他部分将无法正常运行。

【讨论】:

是的,这可能也有效,但似乎 Request.CreateResponse 也有效。 添加 GlobalConfiguration.Configuration 仍然使请求为空。设置请求对我有用,但这并不是我的问题的结束,因为我的 Action 也在调用 Url.Link 并且没有定义路由名称。 帮助设置路由***.com/questions/11779311/… 设置 ControllerContext after 这个调用也给了我这个错误,但仅限于 WebApi 5.0.0。但是如果我在请求 last 上设置 HttpConfiguration 对象,它就可以正常工作。 这很好用,但我不明白为什么会这样。你能在答案中详细说明吗?【参考方案2】:

您可以像这样设置控制器对象以实现可测试性:

var config = new HttpConfiguration();
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/products");
var route = config.Routes.MapHttpRoute("DefaultApi", "api/controller/id");
var routeData = new HttpRouteData(route, new HttpRouteValueDictionary   "controller", "products"  );

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

复制自 Peter Provost 在Unit Testing ASP.NET Web API 上的综合博文。

【讨论】:

您可能还对与此相关的 MS 文档感兴趣:docs.microsoft.com/en-us/aspnet/web-api/overview/… 您可能还需要添加对 System.Web.Http 和 System.Net.Http 的引用【参考方案3】:

对于 Web API 2,您可以简单地添加

controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();

像这样

[TestMethod]
public void GetReturnsProduct()

    // Arrange
    var controller = new ProductsController(repository);
    controller.Request = new HttpRequestMessage();
    controller.Configuration = new HttpConfiguration();

    // Act
    var response = controller.Get(10);

    // Assert
    Product product;
    Assert.IsTrue(response.TryGetContentValue<Product>(out product));
    Assert.AreEqual(10, product.Id);

在控制器上设置请求和配置很重要。否则,测试将失败并出现 ArgumentNullException 或 InvalidOperationException。

请参阅here 了解更多信息。

【讨论】:

【参考方案4】:

WebAPI 1 在此处使用 VB 时遇到类似问题。

我设法在此处混合响应以使其像这样简单地工作:

Dim request As HttpRequestMessage = New HttpRequestMessage()
Return request.CreateResponse(HttpStatusCode.BadRequest, myCustomClassObject, GlobalConfiguration.Configuration)

只是发布以防万一。

【讨论】:

【参考方案5】:

在您的测试类中,创建控制器类的实例。 例如var customerController= new CustomerController();

customerController.Request = new HttpRequestMessage();
customerController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());

【讨论】:

以上是关于使用 Request.CreateResponse 进行 ASP.NET WebApi 单元测试的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET 核心中的 Request.CreateResponse

IHttpActionResult - 如何使用?

ASP .Net中的一个或多个实体Entity Framework的验证失败

关于webApi302跳转的问题

webapi的ActionFilterAttribute可以直接返回数据给客户端吗

测试使用