之前如果对 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

参考资料:

ASP.NET 5 使用 TestServer 进行单元测试的更多相关文章

  1. asp.net core 使用 TestServer 来做集成测试

    asp.net core 使用 TestServer 来做集成测试 Intro 之前我的项目里的集成测试是随机一个端口,每次都真实的启动一个 WebServer,之前也有看到过微软文档上 TestSe ...

  2. ASP.NET Core 对Controller进行单元测试

    单元测试对我们的代码质量非常重要.很多同学都会对业务逻辑或者工具方法写测试用例,但是往往忽略了对Controller层写单元测试.我所在的公司没见过一个对Controller写过测试的.今天来演示下如 ...

  3. Asp.Net MVC3中如何进行单元测试?

    下面我们就以一个示例演示一下如何进行单元测试? public Model.UserInfo UpdateEntity(Model.UserInfo entity) { db.UserInfo.Atta ...

  4. ASP.NET 5 单元测试中使用依赖注入

    相关博文:<ASP.NET 5 使用 TestServer 进行单元测试> 在上一篇博文中,主要说的是,使用 TestServer 对 ASP.NET 5 WebApi 进行单元测试,依赖 ...

  5. 单元测试 – ASP.NET MVC 4 系列

           在开发可测试软件的过程中,单元测试已成为确保软件质量的一个不可或缺部分.测试驱动开发(Test-Driven Development,TDD)是编写单元测试的一种方法,采用该方法的开发人 ...

  6. Asp.Net Core 单元测试正确姿势

    背景 ASP.NET Core 支持依赖关系注入 (DI) 软件设计模式,并且默认注入了很多服务,具体可以参考 官方文档, 相信只要使用过依赖注入框架的同学,都会对此有不同深入的理解,在此无需赘言. ...

  7. ASP.NET Core 入门(3)(单元测试Xunit及Shouldly的使用)

    一.本篇简单介绍下在ASP.NET Core项目如何使用单元测试,例子是使用VS自带的Xunit来测试Web API接口,加上一款开源的断言工具Shouldly,方便写出更简洁.可读行更好的测试代码. ...

  8. Asp.Net Core 轻松学-利用xUnit进行主机级别的网络集成测试

    前言     在开发 Asp.Net Core 应用程序的过程中,我们常常需要对业务代码编写单元测试,这种方法既快速又有效,利用单元测试做代码覆盖测试,也是非常必要的事情:但是,但我们需要对系统进行集 ...

  9. 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 ...

随机推荐

  1. jenkins 登录提示无效

    在自己电脑上的jenkins,有一段时间没有登录,jenkins 登录提示无效 <useSecurity>true</useSecurity>   修改成false <a ...

  2. common.js js中常用方法

    //创建CSS样式段 //classid: CSS样式段ID//font: 字体//size: 字体大小//color: 字体颜色//style: 字体风格function FCMakeCSSClas ...

  3. android shape的使用(转)

    shape用于设定形状,可以在selector,layout等里面使用,有6个子标签,各属性如下: <?xml version="1.0" encoding="ut ...

  4. CharSequence cannot be resolved. It is indirectly referenced from required .class files

    最近在写项目的时候发现会莫名其妙的出现这个编译错误,网上查了下发现自己安装的是JDK1.8造成的 原因:JDK1.8版本现在还不稳定 解决方法:卸载JDK1.8,安装JDK1.7 扩展:发现安装JDK ...

  5. html 5 实现拖放效果

    在html5中要实现拖放操作,相对于以前通过鼠标操作实现,要简单得多,数据安全性也更有保障.只需要以下几步即可. 给被拖拽元素添加draggable属性,如果是文件拖放. 在拖拽元素的dragstar ...

  6. 那点你不知道的XHtml(Xml+Html)语法知识(DTD、XSD)

    什么是XHtml: 摘录网上的一句话,XHTML就是一个扮演着类似HTML的角色的XML. XHtml可当模板引擎应用: CYQ.Data 框架里有一套XHtmlAction模板引擎, 应用在QBlo ...

  7. 【直播】APP全量混淆和瘦身技术揭秘

    [直播]APP全量混淆和瘦身技术揭秘 近些年来移动APP数量呈现爆炸式的增长,黑产也从原来的PC端转移到了移动端,通过逆向手段造成数据泄漏.源码被盗.APP被山寨.破解后注入病毒或广告现象让用户苦不堪 ...

  8. 关于EF6的记录Sql语句 与 EntityFramework.Extend 的诟病

    1.关于EF6的记录Sql语句,一个老生长谈的问题. 他生成的sql语句实在是烂,大家都这样说 2.EF6 更新删除不方便,没有批量操作.所以,有人出了EF6.Extend  大家用起来也很爽 基于以 ...

  9. CCLuaLoadChunksFromZIP加载后的require路径问题

    对于require来说,在LUA中的机制就是搜索path路径了.但对于CCLuaLoadChunksFromZIP加载的LUA文件来说,require的路径又是怎么样的呢? 我在服务器上有一个 oox ...

  10. mysql 的 VARCHAR VARCHAR2

    mysql 里面竟然没有 VARCHAR2 ??