ASP.NET 5 使用 TestServer 进行单元测试
之前如果对 ASP.NET WebAPI 进行单元测试(HttpClient 发起请求,并且可调试 WebAPI),一般采用 Owin 的方式,具体参考:《开发笔记:用 Owin Host 实现脱离 IIS 跑 Web API 单元测试》
示例代码:
public class ValuesWebApiTest : IDisposable
{
private const string HOST_ADDRESS = "http://localhost:8001";
private IDisposable _webApp;
private HttpClient _httClient;
public AdTextUnitWebApiTest()
{
_webApp = WebApp.Start<Startup>(HOST_ADDRESS);
Console.WriteLine("Web API started!");
_httClient = new HttpClient();
_httClient.BaseAddress = new Uri(HOST_ADDRESS);
Console.WriteLine("HttpClient started!");
}
[Fact]
public async Task Get()
{
var response = await _httClient.GetAsync("/api/values");
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine(response.StatusCode);
Console.WriteLine((await response.Content.ReadAsAsync<HttpError>()).ExceptionMessage);
}
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var test = await response.Content.ReadAsStringAsync();
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
public void Dispose()
{
_httClient.Dispose();
_webApp.Dispose();
}
}
本来想在 ASP.NET 5 WebAPI 项目中,也用这一套测试代码,但发现并不适用,因为 ASP.NET WebAPI 2 和 ASP.NET 5 WebAPI 并不是特别一样,比如 Startup.cs 的配置等等,之前使用 WebApp.Start<Startup>(HOST_ADDRESS) 的方式启动 WebAPI 项目,而 ASP.NET 5 WebAPI 变成了这样的:
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
想用 WebApplication.Run 的方式替换掉 WebApp.Start,但发现并不可行,比如 args 的参数问题,自己想的有点简单了,后来 Google 搜索了一些资料,发现 ASP.NET 5 增加了 TestServer,自己找资料配置了很久,看别人的示例代码很简单,但我运行的时候就是各种报错,主要原因是程序包的版本不对,因为我是按照 project.json 的提示安装的,比如 Microsoft.AspNet.TestHost 这个程序包,提示最新版本为 1.0.0-rc2-15960,并且没有 1.0.0-rc1-final 版本,然后我就安装提示安装的 rc2,就报下面的异常:

异常信息:Could not load type 'Microsoft.AspNet.Builder.RequestDelegate' from assembly 'Microsoft.AspNet.Http.Abstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
根据提示,我以为异常原因是没有加载 Microsoft.AspNet.Http.Abstractions 程序集,然后又添加此程序集,重新运行发现还是报错。。。后面具体的过程就不记录了,反正坑很大,根本原因是 Microsoft.AspNet.TestHost 程序包的版本不对,应该安装 1.0.0-rc1-final 版本,我是后来无意间重启 VS2015 发现的。
下面贴一下 ASP.NET 5 进行单元测试的一些代码。
首先 ASP.NET 5 WebAPI 项目 Startup.cs 配置代码:
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Demo.WebApi
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseIISPlatformHandler();
app.UseStaticFiles();
app.UseMvc();
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
ValuesWebApiTest 测试代码:
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Demo.WebApiTests
{
public class ValuesWebApiTest
{
public TestServer _server;
public ValuesWebApiTest()
{
_server = TestServer.Create(app =>
{
var env = app.ApplicationServices.GetRequiredService<IHostingEnvironment>();
var loggerFactory = app.ApplicationServices.GetRequiredService<ILoggerFactory>();
new CNBlogs.Ad.WebApi.Startup(env).Configure(app, env, loggerFactory);
}, services =>
{
services.AddMvc();
services.Configure();
});
}
}
[Fact]
public async Task Get()
{
var response = await _server.CreateClient().GetAsync("/api/values");
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine(response.StatusCode);
Console.WriteLine((await response.Content.ReadAsAsync<HttpError>()).ExceptionMessage);
}
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var test = await response.Content.ReadAsStringAsync();
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}
project.json 配置代码:
{
"frameworks": {
"dnx451": { }
},
"dependencies": {
"Microsoft.AspNet.Mvc.WebApiCompatShim": "6.0.0-rc1-final",
"Microsoft.Net.Http": "2.2.29",
"Microsoft.AspNet.TestHost": "1.0.0-rc1-final",
"xunit": "2.1.0",
"xunit.runner.dnx": "2.1.0-rc1-build204"
},
"commands": {
"test": "xunit.runner.dnx"
}
}
运行测试成功,并且可以 Debug 调试,需要注意 using 引用(没用的我都去掉了),还有程序包的版本号。
注:如果 VS2015 Test Explorer 中找不到测试示例,需要安装最新的 xUnit 程序包。
"xunit": "2.2.0-beta2-build3256",
"xunit.runner.dnx": "2.1.0-rc2-build209"
xUnit 程序包地址:http://myget.org/gallery/xunit
参考资料:
- Integration testing ASP.NET 5 and ASP.NET MVC 6 applications | StrathWeb. A free flowing web tech monologue.
- Writing integration tests for ASP.NET 5
- Testing asp.net 5 vnext middleware from a TestServer - Stack Overflow
ASP.NET 5 使用 TestServer 进行单元测试的更多相关文章
- asp.net core 使用 TestServer 来做集成测试
asp.net core 使用 TestServer 来做集成测试 Intro 之前我的项目里的集成测试是随机一个端口,每次都真实的启动一个 WebServer,之前也有看到过微软文档上 TestSe ...
- ASP.NET Core 对Controller进行单元测试
单元测试对我们的代码质量非常重要.很多同学都会对业务逻辑或者工具方法写测试用例,但是往往忽略了对Controller层写单元测试.我所在的公司没见过一个对Controller写过测试的.今天来演示下如 ...
- Asp.Net MVC3中如何进行单元测试?
下面我们就以一个示例演示一下如何进行单元测试? public Model.UserInfo UpdateEntity(Model.UserInfo entity) { db.UserInfo.Atta ...
- ASP.NET 5 单元测试中使用依赖注入
相关博文:<ASP.NET 5 使用 TestServer 进行单元测试> 在上一篇博文中,主要说的是,使用 TestServer 对 ASP.NET 5 WebApi 进行单元测试,依赖 ...
- 单元测试 – ASP.NET MVC 4 系列
在开发可测试软件的过程中,单元测试已成为确保软件质量的一个不可或缺部分.测试驱动开发(Test-Driven Development,TDD)是编写单元测试的一种方法,采用该方法的开发人 ...
- Asp.Net Core 单元测试正确姿势
背景 ASP.NET Core 支持依赖关系注入 (DI) 软件设计模式,并且默认注入了很多服务,具体可以参考 官方文档, 相信只要使用过依赖注入框架的同学,都会对此有不同深入的理解,在此无需赘言. ...
- ASP.NET Core 入门(3)(单元测试Xunit及Shouldly的使用)
一.本篇简单介绍下在ASP.NET Core项目如何使用单元测试,例子是使用VS自带的Xunit来测试Web API接口,加上一款开源的断言工具Shouldly,方便写出更简洁.可读行更好的测试代码. ...
- Asp.Net Core 轻松学-利用xUnit进行主机级别的网络集成测试
前言 在开发 Asp.Net Core 应用程序的过程中,我们常常需要对业务代码编写单元测试,这种方法既快速又有效,利用单元测试做代码覆盖测试,也是非常必要的事情:但是,但我们需要对系统进行集 ...
- ASP.NET 5 RC1 升级 ASP.NET Core 1.0 RC2 记录
升级文档: Migrating from DNX to .NET Core Migrating from ASP.NET 5 RC1 to ASP.NET Core 1.0 RC2 Migrating ...
随机推荐
- eclipse 项目显示红叉
***修改eclipse 代码提示级别1.单个项目修改项目上右键-->properties-->java compiler-->building-->enable projec ...
- SQL Server
1.通过触发器来级联删除: 具体的触发器代码如下: Create TRIGGER [dbo].[DeleteRelatedProducts] ON [dbo].[ProductCategory] A ...
- select 相关
获取select :获取select 选中的 text : ? 1 $("#ddlregtype").find("option:selected").text( ...
- Python读写文件
Python读写文件1.open使用open打开文件后一定要记得调用文件对象的close()方法.比如可以用try/finally语句来确保最后能关闭文件. file_object = open('t ...
- Powershell 十个常见任务
学习Powershell的时候,基本的语法也了解了一些,但是就是不知道要写些什么?作为一个过来者,和大家一起分享下常见的几个管理任务脚本. 1.更改本地Administrator账号密码 [ADSI] ...
- 我的面板我做主 -- 淘宝UWP中自定义Panel的实现
在Windows10 UWP开发平台上内置的XMAL布局面板包括RelativePanel.StackPanel.Grid.VariableSizedWrapGrid 和 Canvas.在开发淘宝UW ...
- C#设计模式之外观
IronMan之外观 接着上篇观察者内容的“剧情”,没看过的朋友也没关系,篇幅之间有衔接的关系但是影响不大. 需求: 为"兵工厂"提供各种支持,生产了各式各样的"Iron ...
- 微信为什么发布 Mac 版?
因为 Mac 就是好啊就是好啊,就是好…… 打完收工,谢谢,鼓掌 piapiapia……晚安! 这么写在京城行走会不会挨板砖呢?头像已经印到书上满世界的发出去了,虽然考虑到行走江湖求一个稳字,我还特意 ...
- Hystrix框架2--超时
timeout 在调用第三方服务时有些情况需要对服务响应时间进行把控,当超时的情况下进行fallback的处理 下面来看下超时的案例 public class CommandTimeout exten ...
- 程序员的又一春,微信小程序带来的一个赚钱机遇
微信小程序可能是原生的机遇,在程序员面对微信小程序的恐惧中说其实也是我们程序员创业的春天或者挣外快的一个机遇. 为什么这么说呢?且听我慢慢给你分析 成本角度 你想想,会ios开发的可能只会ios,会安 ...