用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中。
【参考资料】
用Owin Host实现脱离IIS跑Web API单元测试的更多相关文章
- 开发笔记:用Owin Host实现脱离IIS跑Web API单元测试
今天在开发一个ASP.NET Web API项目写单元测试时,实在无法忍受之前的笨方法,决定改过自新. 之前Web API的单元测试需要进行以下的操作: 初始配置: 1)在IIS中创建一个站点指定We ...
- 使用Nancy.Host实现脱离iis的Web应用
本篇将介绍如何使用Nancy.Host实现脱离iis的Web应用,在开源任务管理平台TaskManagerV2.0代码里面已经使用了Nancy.Host实现自宿主的Web应用.学习Nancy之前最好了 ...
- 以Self Host的方式来寄宿Web API
Common类及实体定义.Web API的定义请参见我的上一篇文章:以Web Host的方式来寄宿Web API. 一.以Self Host寄宿需要新建一个Console控制台项目(SelfHost) ...
- 旅图beta版 asp.net web api 单元测试
旅图 beta版 asp.net web api 单元测试 测试接口:http://120.27.7.115:1010/Help 测试目的 对每个接口单元进行测试,保证每个接口的可靠性. 单元描述 注 ...
- PCB 脱离IIS的Web应用
在用.net Web编程中,我们写好的Web应用首选会挂在IIS上面,因为它足稳定并且功能齐全,但这不是我们唯一的选择,微软给我们提供了Owin组件,Web应该的宿主可以不再是IIS了,有了Owin后 ...
- 以Web Host的方式来寄宿Web API
一.新建一个Common的类库项目并新建一个测试用的Contact实体类 namespace Common { public class Contact { public string Id { ge ...
- Web Api单元测试写法
例如我们在Web Api项目中有个Controller public class SomeController : ApiController { public HttpResponseMessage ...
- Owin asp.net 脱离 IIS
http://www.cnblogs.com/jesse2013/p/owin-webserver.html
- Web Api Self-Host
今天有在研究SignalR, 发现SignalR可以使用Self-Host的方式,就突发奇想,Web Api是不是也可以使用Self-Host的方式寄宿在Console Application或者其他 ...
随机推荐
- 高仿快车100--实战RadioGroup和RadioButton应用
1.RadioButtonCheckBox的差别: a.单个RadioButton在选中后,通过点击无法变为未选中 单个CheckBox在选中后.通过点击能够变为未选中 b.一组RadioButton ...
- android弹出时间选择框
时间选择框: new DatePickerDialog(this, new OnDateSetListener() { @Override public void onDateSet(DatePick ...
- 透过浏览器看HTTP缓存(转)
作为前端开发人员,对于我们的站点或应用的缓存机制我们能做的似乎不多,但这些却是与我们关注的性能息息相关的部分,站点没有做任何缓存机制,我们的页面可能会因为资源的下载和渲染变得很慢,但大家都知道去找前端 ...
- POJ--2923--Relocation--如压力DP
Relocation Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 2288 Accepted: 950 Descrip ...
- [LeetCode129]Sum Root to Leaf Numbers
题目: Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a nu ...
- 游戏 TRAP(SNRS)AlphaBeta版本
大家好,我是PuzzledBoy,大一(大二快).我是一个独立的游戏开发商,我的梦想是成为一名伟大的艺术家的第九 今天来公布我的第一个独立游戏TRAP(SNRS)的Alpha測试版啦啦啦~~~! 游戏 ...
- uml学习书籍
uml真正实用的书5这是足够.学习如以下的处理: <UML distilled><--><UML和模式应用>-><UML用户指南> 附加两本&l ...
- VC POST表单——登录验证新浪邮箱
1.本机环境: Windows XP SP3.ADSL 2.开发工具: WildPackets OmniPeek V5.1.4 Visual C++ 6.0 IE6.0 FlexEdit V2.3.1 ...
- Linux经常使用的命令(十) - nl
nl命令在linux系统中用来计算文件里行号. nl 能够将输出的文件内容自己主动的加上行号.其默认的结果与 cat -n 有点不太一样. nl 能够将行号做比較多的显示设计,包含位数与是否自己主动补 ...
- 原生js判断css动画结束 css 动画结束的回调函数
原文:原生js判断css动画结束 css 动画结束的回调函数 css3 的时代,css3--动画 一切皆有可能: 传统的js 可以通过回调函数判断动画是否结束:即使是采用CSS技术生成动画效果,Jav ...