用Owin Host实现脱离IIS跑Web API单元测试

开发笔记:用Owin Host实现脱离IIS跑Web API单元测试

今天在开发一个ASP.NET Web API项目写单元测试时,实在无法忍受之前的笨方法,决定改过自新。

之前Web API的单元测试需要进行以下的操作:

初始配置:

1)在IIS中创建一个站点指定Web API项目

2)在hosts加上该站点的IP地址解析

每次修改代码:

3)修改代码之后按F6编译

4)用TestDriven.Net运行单元测试

一看就知道这个方法好土、好笨、好受罪。理想的方式应该是:无需任何初始配置,修改代码之后无需按F6编译,直接运行单元测试,一步完成操作。

今天在受不了旧方式的折磨、经不起理想方式的诱惑的情况下,下定决心要解决这个问题,最终通过Owin Host实现了,通过这篇博文分享一下。

用Owin Host实现的思路很简单,就是在单元测试中以Owin Host运行ASP.NET Web API站点,然后单元测试代码直接请求这个Owin Host站点进行测试。

我们的Web API项目是基于ASP.NET 4.5 + ASP.NET Web API 5.2.3开发的,没有OWIN相关的代码,所以先要在Web API项目中添加一些代码 ,以让Owin Host能够加载之。

首先nuget安装Owin包包(IAppBuilder在此包中):

PM> Install-Package Owin

然后添加Startup.cs:

public class Startup
{
    public void Configuartion(IAppBuilder app)
    {
    }
}

接着nuget安装Microsoft.AspNet.WebApi.Owin包包(app.UseWebApi扩展方法在此包中)

PM> Install-Package Microsoft.AspNet.WebApi.Owin

在Startup.Configuratrion方法中添加代码,调用WebApiConfig.Register方法(这个是之前已经实现的,路由配置就在其中)配置HttpConfiguration,然后将之注册到OWIN的管线中。

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var configuraton = new HttpConfiguration();
        WebApiConfig.Register(configuraton);
        app.UseWebApi(configuraton);
    }
}

Web API项目只需这样简单改造一下,就可以支持Owin Host,无任何副作用,不影响用IIS部署站点。

单元测试代码的改造也很简单,只需在跑测试之前用Microsoft.Owin.Hosting中的WebApp.Start()方法加载Web API站点。

首先nuget安装Owin Host的包包:

PM> Install-Package Microsoft.Owin.Hosting
PM> Install-Package Microsoft.Owin.Host.HttpListener

接着在测试类的构造函数中用WebApp.Start()启动Web API站点:

public class CommentsWebApiTest : IDisposable
{
    private const string HOST_ADDRESS = "http://localhost:8001";
    private IDisposable _webApp;
    public CommentsWebApiTest()
    {
        _webApp = WebApp.Start<Startup>(HOST_ADDRESS);
        Console.WriteLine("Web API started!");
    }

    public void Dispose()
    {
        _webApp.Dispose();
    }
}

然后就可以脱离IIS无比轻松地进行Web API的单元测试了。

下面来实际体验一下:

1)在Web API项目中实现一个ApiController

public class CommentsController : ApiController
{
    [Route("blogposts/{postId}/comments")]
    public async Task<IHttpActionResult> Get(int postId)
    {
        var comments = new Comment[] { new Comment {
            PostId = postId,
            Body = "Coding changes the world1" } };
        return Ok<Comment[]>(comments);
    }
}

2)编写基于Owin Host跑Web API站点的单元测试代码

public class CommentsWebApiTest : IDisposable
{
    private const string HOST_ADDRESS = "http://localhost:8001";
    private IDisposable _webApp;
    private HttpClient _httClient;

    public CommentsWebApiTest()
    {
        _webApp = WebApp.Start<Startup>(HOST_ADDRESS);
        Console.WriteLine("Web API started!");
        _httClient = new HttpClient();
        _httClient.BaseAddress = new Uri(HOST_ADDRESS);
        Console.WriteLine("HttpClient started!");
    }

    public void Dispose()
    {
        _httClient.Dispose();
        _webApp.Dispose();
    }

    [Fact]
    public async Task GetComments()
    {
        var postId = 1;
        var response = await _httClient.GetAsync($"/blogposts/{postId}/comments");
        if(response.StatusCode != HttpStatusCode.OK)
        {
            Console.WriteLine(await response.Content.ReadAsStringAsync());
        }
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        var comments = await response.Content.ReadAsAsync<Comment[]>();
        Assert.NotEmpty(comments);
        Assert.Equal(postId, comments[0].PostId);
        Assert.Equal("Coding changes the world", comments[0].Body);
    }
}

注:除了nuget安装Microsoft.Owin.Hosting与Microsoft.Owin.Host.HttpListener包包,还要安装Microsoft.AspNet.WebApi.Client包包(ReadAsAsync<Comment[]>在此包中)。

3)运行单元测试:在单元测试方法中点击鼠标右键并点击Run Test(s)(用的是TestDriven.Net,会在单元测试前自动进行编译)

4)查看单元测试结果,验证测试Web API的理想方式是否实现:

Output from WebApiTests.CommentsWebApiTest.GetComments:
  Web API started!
  HttpClient started!

1 passed, 0 failed, 0 skipped, took 4.91 seconds (xUnit.net 1.9.2 build 1705).

测试通过!理想方式实现!

这次经历再次证明了,当有一个问题影响你写代码的乐趣时,一定要尽早下定决心解决它,否则它浪费的时间很可能是解决这个问题所需时间的n倍,而且很多时候解决一个问题的难易程度取决于你下的决心有多大。

【更新】

需要注意一个地方,在单元测试中以owin host运行web api站点时,配置信息(比如数据库连接字符串)是从单元测试项目的app.config中读取,而不是从web api项目的web.config中读取,所以要将web.config中的相关配置复制到app.config中。

【参考资料】

ASP.NET Web API Integration Testing with One Line of Code

时间: 2024-10-23 12:42:59

用Owin Host实现脱离IIS跑Web API单元测试的相关文章

开发笔记:用Owin Host实现脱离IIS跑Web API单元测试

今天在开发一个ASP.NET Web API项目写单元测试时,实在无法忍受之前的笨方法,决定改过自新. 之前Web API的单元测试需要进行以下的操作: 初始配置: 1)在IIS中创建一个站点指定Web API项目 2)在hosts加上该站点的IP地址解析 每次修改代码: 3)修改代码之后按F6编译 4)用TestDriven.Net运行单元测试 一看就知道这个方法好土.好笨.好受罪.理想的方式应该是:无需任何初始配置,修改代码之后无需按F6编译,直接运行单元测试,一步完成操作. 今天在受不了旧

使用OWIN 构建自宿主ASP.NET Web API 2

--Use OWIN to Self-Host ASP.NET Web API 2 原文链接:http://www.asp.net/web-api/overview/hosting-aspnet-web-api/use-owin-to-self-host-web-api 摘要:ASP.NET Web API 2拥有符合RESTFUL风格,原生支持HTML协议,解耦IIS和windows server服务器等诸多优秀特性.本文讲述如何使用OWIN构建ASP.NET Web API 2.在翻译的基础

以Self Host的方式来寄宿Web API

Common类及实体定义.Web API的定义请参见我的上一篇文章:以Web Host的方式来寄宿Web API. 一.以Self Host寄宿需要新建一个Console控制台项目(SelfHost) 这个项目也需要引用之前定义的WebApi项目或者把WebApi.dll放到此项目的执行Bin目录下, 另外,需要引用的DLLs如下: System.Web.Http.dll  (C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 4\Assem

Web Api单元测试写法

例如我们在Web Api项目中有个Controller public class SomeController : ApiController { public HttpResponseMessage Get() { // 一些操作 return Request.CreateResponse(HttpStatusCode.OK, someModel); } } 如果你在单元测试中直接调用 SomeController 的Get()方法,那么你将会收到一个Exception提示Request为Nu

JSON Web Token in ASP.NET Web API 2 using Owin

In the previous post Decouple OWIN Authorization Server from Resource Server we saw how we can separate the Authorization Server and the Resource Server by unifying the "decryptionKey" and "validationKey" key values in machineKey node

OWIN support for the Web API 2 and MVC 5 integrations in Autofac

Currently, in the both the Web API and MVC frameworks, dependency injection support does not come into play until after the OWIN pipeline has started executing. This is simply a result of the OWIN support being added to both frameworks after their in

[ASP.NET Web API]如何Host定义在独立程序集中的Controller

通过< ASP.NET Web API的Controller是如何被创建的?>的介绍我们知道默认ASP.NET Web API在Self Host寄宿模式下用于解析程序集的AssembliesResolver是一个DefaultAssembliesResolver对象,它只会提供 当前应用程序域已经加载的程序集.如果我们将HttpController定义在非寄宿程序所在的程序集中(实际上在采用Self Host寄宿模式下,我们基本上都会选择在独立的项目定义HttpController类型),即

ASP.NET Web API 安全筛选器

原文:https://msdn.microsoft.com/zh-cn/magazine/dn781361.aspx 身份验证和授权是应用程序安全的基础.身份验证通过验证提供的凭据来确定用户身份,而授权则决定是否允许用户执行请求的操作.安全的 Web API 身份验证基于确定的身份请求和授权用户请求的资源访问. 您可以在 ASP.NET Web API 中使用 ASP.NET Web API 管道中提供的扩展点,以及使用由主机提供的选项来实现身份验证.对于 ASP.NET Web API 的第一

ASP.NET Web Api 2 接口API文档美化之Swagger

使用第三方提供的swgger ui 可有效提高 web api 接口列表的阅读性,并且可以在页面中测试服务接口. 但本人在查阅大量资料并进行编码测试后,发现大部分的swagger实例并不能有效运行.例如如下两个网址:http://www.cnblogs.com/caodaiming/p/4156476.html 和 http://bitoftech.net/2014/08/25/asp-net-web-api-documentation-using-swagger/.经过本人的一番折腾,最终发现