.netcore持续集成测试篇之搭建内存服务器进行集成测试一

系列目录html

在web项目里,咱们把每一层的代码的单元测试都经过并不表明程序能正常运行,由于这个过程缺失了http管道,不少时候咱们还还须要把项目布在iis环境中或者在vs里启动iis express服务器进行集成测试.对于返回view的的方法咱们一般是在浏览器中输入地址进行测试,对于返回数据的方法则使用诸如postman,fiddler,httpMaster pro,http debugger等工具进行测试.在这些工具中,postman相对好用,不但提供了测试数据的分组功能,还能够编写脚原本完成一些自动化工做,好比自动添加固定http头等.然而即使诸如postman这么强大,依赖有不少不方便的地方.一旦方法过多,管理起来很不方便.而且构造复杂json或者formdata数据更是让人心力绞悴,稍有一点格式错误就致使整个测试通不过,严重影响对错误点位置的判断.更为重要的一点是,咱们不管是在页面中输入地址,仍是使用postman工具更多的是被动的去解决问题,也就是说等错误出现了之后咱们才去测试相应的方法,不多见有谁使用postman把全部方法所有都跑一遍.web

幸运的是.微软在把.net升级到.net core以后,asp.net core 能够搭建一个内存服务器来完成集成测试,这样咱们即可以不依赖于特定环境来测试咱们的代码.这样咱们就在项目发布前能够先运行一下集成测试确保各方法都是可访问的,减小项目上线后出现一些简单错误的机率.express

下面咱们介绍如何搭建集成测试环境json

产生咱们使用VisualStudio自带的模板建立一个Asp.net core web项目,在出现的对话框选项中选择mvc(固然也能够不使用mvc项目,这里不了演示方便起见).新建完mvc项目后,默认会有一个HomeController,想必你们都很熟悉了.此时咱们再新建一个HelloWorld控制器,这个控制器目前只有一个Hello方法,代码以下c#

public class HelloWorldController : Controller
    {
        public IActionResult Hello()
        {
            return Content("Hello,World");
        }
    }

而后咱们使用VisualStudio自带的Xunit模板建立一个测试项目(新建项目的时候切换到.net core标签,里面有Xunit测试项目模板)后端

此时,在测试项目里须要添加Microsoft.AspNetCore.TestHost Nuget包才能够进行集成测试.api

须要注意的是,这个包要安装在测试项目里,而不是core Mvc项目里浏览器

咱们新建一个名为mvc20的测试类,代码以下服务器

public class mvc20
    {
        private readonly HttpClient _client;

        public mvc20()
        {
            var builder = new WebHostBuilder()
                .UseContentRoot(@"E:\personal project\newTest2018\ConsoleApp1\CoreMvc")
                .UseEnvironment("Development")
                .UseStartup<CoreMvc.Startup>();
            var server = new TestServer(builder);
             _client = server.CreateClient();
        }

        [Fact]
        public async Task SimpleGet()
        {
            var response = await _client.GetAsync("/HelloWorld/Hello");
            response.EnsureSuccessStatusCode();
            var responseStr = await response.Content.ReadAsStringAsync();
            Assert.Equal("Hello,World", responseStr);
        }
    }

配置详解

下面咱们来详细分析这段代码mvc

咱们先来看构造函数里的代码,这里的第一部分是建立一个WebHostBuilder,若是了解过.net core的同事可能对这段代码感到很熟悉,其实mvc项目也是经过WebHostBuilder建立一个webhost,咱们打开刚建立的mvc项目,打开program入口类能够看到以下代码

public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();

能够看到BuildWebHost方法里面使用了WebHost类来建立一个默认WebHostBuilder,这个方法里面也有UseStartup方法,其实像亲朋ContentRoot,UseEnvironment这些方法也能够在mvc项目里用,早期的.net core 项目模板生成的方法确实是这样的,只是在.net core 2.0进行了更进一步的抽象,ContentRoot路径,默认工做环境都按照惯例提供,再也不须要手动指定.可是测试项目的工做环境和mvc项目的运行环境并不在同一个目录,所以这里须要手工指定.

UseContentRoot

此方法用于指定项目运行时资源文件的根目录,一般状况下是建立项目的目录,以上目录你们根据建立项目的路径来选择,不要盲目拷贝以上代码.

UseEnvironment

此方法用于指定项目的运行环境,这里咱们指定为Development环境,这个环境是开发环境约定的默认环境,至于为何须要指定工做环境,由于不少时候开发环境和线上环境中使用到的组件是不同的,这在.net core项目里尤为明显,好比说线上环境中咱们使用的是正式的EntityFramework,而在工做环境下为了效率咱们更倾向使用一个内存EntityFramework.还有一些工具类的框架只是在开发环境中使用的,线上环境并不须要它.

这个概念可能很容易理解,可是相信你们仍然看的一头蒙圈,为何是Development,而不是Develop,debug呢,其实这个变量名是在mvc项目下的Properties里面的launchSettings.json里定义的.

avatar

所以若是咱们提供的参数是"Development",mvc项目启动的时候就把它和这个文件匹配,若是匹配成功则当前工做环境就是Development环境.

到于它是怎么用,能够查看Startup.cs文件,里面会注入IHostingEnvironment 对象实例,其中里面的env.IsDevelopment就是经过这个值来判断当前工做环境是不是Development环境,若是是工做环境,咱们能够添加一些只有在工做环境中使用的代码.

UseStartup

此方法用于指定一个Startup文件,Startup文件在mvc5项目里也有,主要是关于中间件的配置,只是mvc5在启动的时候自动调用一个名为Startup的文件(mvc5项目里这个文件不是必须的),而.net core里显式指定一个startup文件,这样就必须指定一个startup文件(名称没必要须是startup,能够是任意名,这里是显式指定的,所以程序中能找到). net core项目里startup文件必须指定不然整个项目就是一个普通操控台应该程序,无法实现http功能,不管是mvc,webapi仍是基本的http请求在.net core里都做为一个中间件,要使用必须配置.

回到测试方法里,这个startup文件直接指定为mvc项目里的startup文件便可,而且必需要这样,若是测试环境中的startup文件和mvc项目里的不同测试就显得没有意义了.

TestServer

在测试环境里经过new方式建立一个TestServer,构造函数接收一个IWebHostBuilder类型的参数,咱们把上面建立的WebHostBuilder传入便可.

建立HttpClient

TestServer对象能够建立一个HttpClient对象,利用HttpClient对象咱们即可以构建Http请求了.

须要说明的是这个HttpClient并没什么特殊的,它就是System.net.http下的httpclient,想必你们多少都用到过.

下面咱们来看测试方法,测试方法主要就是经过HttpClient来发送Http请求,这里的代码相信你们都并不陌生.

须要特别注意的是,这个测试方法和以往的不太相同,是一个async Task标识的异步方法,之因此要使用异步方法是由于HttpClient里的方法都是异步的,若是尝试使用同步的方法获取结果,很容易形成死锁.可能你们在工做中也确实使用过xxx.Result来同步阻塞获取异步结果,而且能正确返回真,可是阻塞HttpClient里的异步方法不少时候都会形成死锁.至于缘由你们能够查看这篇文章

https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

小贴士,如何在Main方法里面调用异步函数,C# 7.1以前版本的Main方法是不支持异步Main方法的,这给测试异步方法带来了很大的不便,c# 7.1开始支持异步Main方法,咱们能够把Main方法标识为Async Task Main(string[] args).而后咱们在visual studio里对着项目右键点击属性,在Build标签下选择高级,弹出的对话框里语言版本下拉列表选择c# 7.1或者更高(写本文时,VisualStudio最高支持C# 7.3).这样异步Main方法便能编译经过了.

avator

下面言归正传,测试方法里的代码相必你们都很熟悉了,这里有一点可能有些同事没有遇到过那就是EnsureSuccessStatusCode从字面上看它的意思是保证成功状态,实际上它并非保证请求必定可以返回成功,而是返回的状态码不是200的时候就抛出一个异常.

须要注意的是EnsureSuccessStatusCode请求返回的必须是200才能经过,201,204这样的状态码也会抛出异常.你们在开发过程当中必定要根据实际状况来决定是否使用它.通常状况下先后端分离的项目里不少项目组都对http请求返回的结果进行了封闭,无论成功或者失败都返回200,具体成功失败是经过一个额外的其它字段来确实的.这种状况下须要使用EnsureSuccessStatusCode,若是有对外接口不少时候会返回201,204,304,403等http状态,这时候若是 使EnsureSuccessStatusCode则结果不是咱们期待的.