.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則結果不是咱們期待的.

相關文章
相關標籤/搜索