在 Visual Studio 2013 中使用 HttpClient 进行单元测试/集成测试 Web API

Posted

技术标签:

【中文标题】在 Visual Studio 2013 中使用 HttpClient 进行单元测试/集成测试 Web API【英文标题】:Unit Testing / Integration Testing Web API with HttpClient in Visual Studio 2013 【发布时间】:2016-05-27 05:19:18 【问题描述】:

我很难用 Visual Studio 2013 测试我的 API 控制器。我的一个解决方案有一个 Web API 项目和一个测试项目。在我的测试项目中,我有一个单元测试:

[TestMethod]
public void GetProduct()

    HttpConfiguration config = new HttpConfiguration();
    HttpServer _server = new HttpServer(config);

    var client = new HttpClient(_server);

    var request = new HttpRequestMessage
    
        RequestUri = new Uri("http://localhost:50892/api/product/hello"),
        Method = HttpMethod.Get
    ;

    request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    using (var response = client.SendAsync(request).Result)
    
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);

        var test = response.Content.ReadAsAsync<CollectionListDTO>().Result;
    

我不断收到 404。我尝试使用 Visual Studio (IIS Express) 的一个实例运行我的 API,并尝试在另一个实例中调试此单元测试。但没有运气。我已经验证我可以将此 URL 放在浏览器中(当一个 Visual Studio 正在调试时)并且我看到了我的 JSON 响应。但我不知道如何让它与我的单元测试和HttpClient一起工作。我试图在网上找到示例,但似乎找不到。有人可以帮忙吗?

更新 1: 我尝试添加路线,但没有任何反应。

HttpConfiguration config = new HttpConfiguration();

// Added this line
config.Routes.MapHttpRoute(name: "Default", routeTemplate: "api/product/hello/");

HttpServer _server = new HttpServer(config);

var client = new HttpClient(_server);

[...rest of code is the same]

这是我的 API 控制器

[HttpGet]
[Route("api/product/hello/")]
public IHttpActionResult Hello()

     return Ok();

更新分辨率: 如果我在没有HttpServer 对象的情况下新建HttpClient,我就能让它工作。不过,我仍然需要运行两个 VS 实例。 1 运行我的 API 代码,另一个运行单元测试。

这是一个工作方法。

[TestMethod]
public void Works()

    var client = new HttpClient(); // no HttpServer

    var request = new HttpRequestMessage
    
        RequestUri = new Uri("http://localhost:50892/api/product/hello"),
        Method = HttpMethod.Get
    ;

    request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    using (var response = client.SendAsync(request).Result)
    
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
    

任何人都知道为什么它不能与 HttpServerHttpConfiguration 传递到 HttpClient 一起工作吗?我见过很多使用这个的例子。

【问题讨论】:

可能没什么区别,但为什么不直接使用GetAsync呢? 您是否在启动时使用 OWIN 管道?您可能需要使用TestServer。 blogs.msdn.microsoft.com/webdev/2013/11/26/… 我没有使用owin。 你使用的是什么版本的 asp.net-mvc web api? 您要测试的方法的代码在哪里?这看起来像是一个集成测试,因为您没有模拟/伪造任何依赖项。 【参考方案1】:

参考以下文章我能够做到...

ASP.NET Web API integration testing with in-memory hosting

通过使用 HttpServerHttpConfiguration 传递到 HttpClient。在以下示例中,我创建了一个使用属性路由的简单 ApiController。我将HttpConfiguration 配置为映射属性路由,然后将其传递给新的HttpServer。然后HttpClient 可以使用配置的服务器对测试服务器进行集成测试调用。

public partial class MiscUnitTests 
    [TestClass]
    public class HttpClientIntegrationTests : MiscUnitTests 

        [TestMethod]
        public async Task HttpClient_Should_Get_OKStatus_From_Products_Using_InMemory_Hosting() 

            var config = new HttpConfiguration();
            //configure web api
            config.MapHttpAttributeRoutes();

            using (var server = new HttpServer(config)) 

                var client = new HttpClient(server);

                string url = "http://localhost/api/product/hello/";

                var request = new HttpRequestMessage 
                    RequestUri = new Uri(url),
                    Method = HttpMethod.Get
                ;

                request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                using (var response = await client.SendAsync(request)) 
                    Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
                
            
        
    

    public class ProductController : ApiController 
        [HttpGet]
        [Route("api/product/hello/")]
        public IHttpActionResult Hello() 
            return Ok();
        
    

无需运行另一个 VS 实例即可对控制器进行集成测试。

以下简化版本的测试也同样有效

var config = new HttpConfiguration();
//configure web api
config.MapHttpAttributeRoutes();

using (var server = new HttpServer(config)) 

    var client = new HttpClient(server);

    string url = "http://localhost/api/product/hello/";

    using (var response = await client.GetAsync(url)) 
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
    

在您的情况下,您需要确保正确配置服务器以匹配您的 Web api 设置。这意味着您必须使用 HttpConfiguration 对象注册您的 api 路由。

var config = new HttpConfiguration();
//configure web api
WebApiConfig.Register(config);
//...other code removed for brevity

【讨论】:

您是否可以向我发送此解决方案的副本?我从字面上复制了代码,但它似乎在我的解决方案中不起作用。所以我认为有一些不同的配置。我的项目属性具有在 IIS Express 下以端口号运行的项目。项目 url 有这个“localhost:50892”。我曾尝试在单元测试中使用端口但没有端口号,但没有成功。还是 404。 内存测试请求实际上并没有到达网络,因此与 IIS 或 IIS Express 无关。 HttpServer 一个 DelegatingHandler 正在处理 HttpClient 正在发出的请求。不需要端口,默认值为http://localhost,就像我的示例中一样。我从您的帖子中获取了确切的代码,只更改了 url 的主机并将控制器配置为使用属性路由。 复制我的答案中的确切单元测试类并在您的测试项目中运行它。它应该运行并通过。然后,您可以查看它是如何完成的,并尝试将相同的技术应用到您的实际测试中。没有多余的东西。您在那里看到的一切都是它的编写和测试方式。 我的猜测是MapHttpAttributeRoutes 在当前程序集中搜索具有 Route 特定属性的 ApiControllers。当我将 ProductController 从 Sample 项目复制到测试项目时,它起作用了。我可能需要查看 github 或 codeplex 上的源代码,看看该方法的作用。 我刚刚遇到了完全相同的问题,当我只调用config.MapHttpAttributeRoutes() 时,我的路由/控制器没有被发现。当我通过调用例如 WebApiConfig.Register(config); 添加对我的 WebApi 项目的显式引用时,它可以工作! (仅添加var ctrl = new ValuesController(); 也可以!)我的猜测是这与未使用的程序集有关,运行时未加载。这意味着未加载 WebApi,因此不会扫描和发现路由/控制器

以上是关于在 Visual Studio 2013 中使用 HttpClient 进行单元测试/集成测试 Web API的主要内容,如果未能解决你的问题,请参考以下文章

使用平台工具集 v120 (Visual Studio 2013) 在 Visual Studio 2015 中创建 C++/CLI 项目

Intel parallel studio 2017 集成在visual studio 2013 中,现在如何集成到visual studio 2015

在 Visual Studio 2013 中使用 Roslyn 编译器

在 Visual Studio 2013 中使用 angularjs 材料设计

如何在 Visual Studio 2013 中使用 NuGet 3.0?

Visual Studio中的环境变量(以Visual Studio 2013为例)