最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Asp.Net Core利用xUnit進行主機級別的網(wǎng)絡(luò)集成測試詳解

 更新時間:2018年12月11日 10:24:44   作者:Ron.liang  
這篇文章主要給大家介紹了關(guān)于Asp.Net Core利用xUnit進行主機級別的網(wǎng)絡(luò)集成測試的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們來一起看看吧

前言

在開發(fā) Asp.Net Core 應(yīng)用程序的過程中,我們常常需要對業(yè)務(wù)代碼編寫單元測試,這種方法既快速又有效,利用單元測試做代碼覆蓋測試,也是非常必要的事情;但是,但我們需要對系統(tǒng)進行集成測試的時候,需要啟動服務(wù)主機,利用瀏覽器或者Postman 等網(wǎng)絡(luò)工具對接口進行集成測試,這就非常的不方便,同時浪費了大量的時間在重復(fù)啟動應(yīng)用程序上;今天要介紹就是如何在不啟動應(yīng)用程序的情況下,對 Asp.Net Core WebApi 項目進行網(wǎng)絡(luò)集成測試。

一、建立項目

1.1 首先我們建立兩個項目,Asp.Net Core WebApi 和 xUnit 單元測試項目,如下

1.2 上圖的單元測試項目 Ron.XUnitTest 必須應(yīng)用待測試的 WebApi 項目 Ron.TestDemo

1.3 接下來打開 Ron.XUnitTest 項目文件 .csproj,添加包引用

Microsoft.AspNetCore.App
Microsoft.AspNetCore.TestHost

1.4 為什么要引用這兩個包呢,因為我剛才創(chuàng)建的 WebApi 項目是引用 Microsoft.AspNetCore.App 的,至于 Microsoft.AspNetCore.TestHost,它是今天的主角,為了使用測試主機,必須對其進行引用,下面會詳細說明

二、編寫業(yè)務(wù)

2.1 創(chuàng)建一個接口,代碼如下

 [Route("api/[controller]")]
 [ApiController]
 public class ValuesController : ControllerBase
 {
 private IConfiguration configuration;
 public ValuesController(IConfiguration configuration)
 {
  this.configuration = configuration;
 }

 [HttpGet("{id}")]
 public ActionResult<int> Get(int id)
 {
  var result= id + this.configuration.GetValue<int>("max");

  return result;
 }
 }

2.1 接口代碼非常簡單,接受一個參數(shù) id,然后和配置文件中獲取的值 max 相加,然后輸出結(jié)果給客戶端

三、編寫測試用例

3.1 為了能夠使用主機集成測試,我們需要使用類

Microsoft.AspNetCore.TestHost.TestServer

3.2 我們來看一下 TestServer 的源碼,代碼較長,你可以直接跳過此段,進入下一節(jié) 3.3

 public class TestServer : IServer
 {
 private IWebHost _hostInstance;
 private bool _disposed = false;
 private IHttpApplication<Context> _application;

 public TestServer(): this(new FeatureCollection())
 {
 }

 public TestServer(IFeatureCollection featureCollection)
 {
  Features = featureCollection ?? throw new ArgumentNullException(nameof(featureCollection));
 }

 public TestServer(IWebHostBuilder builder): this(builder, new FeatureCollection())
 {
 }
 
 public TestServer(IWebHostBuilder builder, IFeatureCollection featureCollection): this(featureCollection)
 {
  if (builder == null)
  {
  throw new ArgumentNullException(nameof(builder));
  }

  var host = builder.UseServer(this).Build();
  host.StartAsync().GetAwaiter().GetResult();
  _hostInstance = host;
 }

 public Uri BaseAddress { get; set; } = new Uri("http://localhost/");

 public IWebHost Host
 {
  get
  {
  return _hostInstance
   ?? throw new InvalidOperationException("The TestServer constructor was not called with a IWebHostBuilder so IWebHost is not available.");
  }
 }

 public IFeatureCollection Features { get; }

 private IHttpApplication<Context> Application
 {
  get => _application ?? throw new InvalidOperationException("The server has not been started or no web application was configured.");
 }

 public HttpMessageHandler CreateHandler()
 {
  var pathBase = BaseAddress == null ? PathString.Empty : PathString.FromUriComponent(BaseAddress);
  return new ClientHandler(pathBase, Application);
 }

 public HttpClient CreateClient()
 {
  return new HttpClient(CreateHandler()) { BaseAddress = BaseAddress };
 }

 public WebSocketClient CreateWebSocketClient()
 {
  var pathBase = BaseAddress == null ? PathString.Empty : PathString.FromUriComponent(BaseAddress);
  return new WebSocketClient(pathBase, Application);
 }

 public RequestBuilder CreateRequest(string path)
 {
  return new RequestBuilder(this, path);
 }

 public async Task<HttpContext> SendAsync(Action<HttpContext> configureContext, CancellationToken cancellationToken = default)
 {
  if (configureContext == null)
  {
  throw new ArgumentNullException(nameof(configureContext));
  }

  var builder = new HttpContextBuilder(Application);
  builder.Configure(context =>
  {
  var request = context.Request;
  request.Scheme = BaseAddress.Scheme;
  request.Host = HostString.FromUriComponent(BaseAddress);
  if (BaseAddress.IsDefaultPort)
  {
   request.Host = new HostString(request.Host.Host);
  }
  var pathBase = PathString.FromUriComponent(BaseAddress);
  if (pathBase.HasValue && pathBase.Value.EndsWith("/"))
  {
   pathBase = new PathString(pathBase.Value.Substring(0, pathBase.Value.Length - 1));
  }
  request.PathBase = pathBase;
  });
  builder.Configure(configureContext);
  return await builder.SendAsync(cancellationToken).ConfigureAwait(false);
 }

 public void Dispose()
 {
  if (!_disposed)
  {
  _disposed = true;
  _hostInstance.Dispose();
  }
 }

 Task IServer.StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
 {
  _application = new ApplicationWrapper<Context>((IHttpApplication<Context>)application, () =>
  {
  if (_disposed)
  {
   throw new ObjectDisposedException(GetType().FullName);
  }
  });

  return Task.CompletedTask;
 }

 Task IServer.StopAsync(CancellationToken cancellationToken)
 {
  return Task.CompletedTask;
 }

 private class ApplicationWrapper<TContext> : IHttpApplication<TContext>
 {
  private readonly IHttpApplication<TContext> _application;
  private readonly Action _preProcessRequestAsync;

  public ApplicationWrapper(IHttpApplication<TContext> application, Action preProcessRequestAsync)
  {
  _application = application;
  _preProcessRequestAsync = preProcessRequestAsync;
  }

  public TContext CreateContext(IFeatureCollection contextFeatures)
  {
  return _application.CreateContext(contextFeatures);
  }

  public void DisposeContext(TContext context, Exception exception)
  {
  _application.DisposeContext(context, exception);
  }

  public Task ProcessRequestAsync(TContext context)
  {
  _preProcessRequestAsync();
  return _application.ProcessRequestAsync(context);
  }
 }
 }

3.3 TestServer 類代碼量比較大,不過不要緊,我們只需要關(guān)注它的構(gòu)造方法就可以了

 public TestServer(IWebHostBuilder builder)
  : this(builder, new FeatureCollection())
 {
 }

3.4 其構(gòu)造方法接受一個 IWebHostBuilder 對象,只要我們傳入一個 WebHostBuilder 就可以創(chuàng)建一個測試主機了

3.5 創(chuàng)建測試主機和 HttpClient 客戶端,我們在測試類 ValuesUnitTest 編寫如下代碼

 public class ValuesUnitTest
 {
 private TestServer testServer;
 private HttpClient httpCLient;

 public ValuesUnitTest()
 {
  testServer = new TestServer(new WebHostBuilder().UseStartup<Ron.TestDemo.Startup>());
  httpCLient = testServer.CreateClient();
 }

 [Fact]
 public async void GetTest()
 {
  var data = await httpCLient.GetAsync("/api/values/100");
  var result = await data.Content.ReadAsStringAsync();

  Assert.Equal("300", result);
 }
 }

代碼解釋

這段代碼非常簡單,首先,我們聲明了一個 TestServer 和 HttpClient 對象,并在構(gòu)造方法中初始化他們; TestServer 的初始化是由我們 new 了一個 Builder 對象,并指定其使用待測試項目 Ron.TestDemo 中的 Startup 類來啟動,這樣我們能可以直接使用待測試項目的路由和管道了,甚至我們無需指定測試站點,因為這些都會在 TestServer 自動配置一個 localhost 的主機地址

3.7 接下來就是創(chuàng)建了一個單元測試的方法,直接使用剛才初始化的 HttpClient 對象進行網(wǎng)絡(luò)請求,這個時候,我們只需要知道 Action 即可,同時傳遞參數(shù) 100,最后斷言服務(wù)器輸出值為:"300",回顧一下我們創(chuàng)建的待測試方法,其業(yè)務(wù)正是將客戶端傳入的 id 值和配置文件 max 值相加后輸出,而 max 值在這里被配置為 200

3.8 運行單元測試

3.9 測試通過,可以看到,測試達到了預(yù)期的結(jié)果,服務(wù)器正確返回了計算后的值

四、配置文件注意事項

4.1 在待測試項目中的配置文件 appsettings.json 并不會被測試主機所讀取,因為我們在上面創(chuàng)建測試主機的時候沒有調(diào)用方法

WebHost.CreateDefaultBuilder

4.2 我們只是創(chuàng)建了一個 WebHostBuilder 對象,非常輕量的主機配置,簡單來說就是無配置,如果對于 WebHost.CreateDefaultBuilder 不理解的同學(xué),建議閱讀我的文章 asp.netcore 深入了解配置文件加載過程.

4.3 所以,為了能夠在單元測試中使用項目配置文件,我在 Ron.TestDemo 項目中的 Startup 類加入了下面的代碼

 public class Startup
 {
 public Startup(IConfiguration configuration, IHostingEnvironment env)
 {
  this.Configuration = new ConfigurationBuilder()
  .AddJsonFile("appsettings.json")
  .AddEnvironmentVariables()
  .SetBasePath(env.ContentRootPath)
  .Build();
 }

 public IConfiguration Configuration { get; }

 // This method gets called by the runtime. Use this method to add services to the container.
 public void ConfigureServices(IServiceCollection services)
 {
  services.AddSingleton<IConfiguration>(this.Configuration);
  services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
 }
 }

4.4 其目的就是手動讀取配置文件,重新初始化 IConfiguration 對象,并將 this.Configuration 對象加入依賴注入容器中

結(jié)語

  • 本文從單元測試入手,針對常見的系統(tǒng)集成測試提供了另外一種便捷的測試方案,通過創(chuàng)建 TestServer 測試主機開始,利用主機創(chuàng)建 HttpCLient 對象進行網(wǎng)絡(luò)集成測試
  • 減少重復(fù)啟動程序和測試工具,提高了測試效率
  • 充分利用了 Visual Studio 的優(yōu)勢,既可以做單元測試,還能利用這種測試方案進行快速代碼調(diào)試
  • 最后,還了解如何通過 TestServer 主機加載待測試項目的配置文件對象 IConfiguration

示例代碼下載

http://xiazai.jb51.net/201812/yuanma/Ron.TestDemo_jb51.rar

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • LINQ操作數(shù)組代碼(交集,并集,差集,最值,平均,去重復(fù))

    LINQ操作數(shù)組代碼(交集,并集,差集,最值,平均,去重復(fù))

    數(shù)組是大學(xué)里經(jīng)常拿來做算法練習(xí)的對象。一些經(jīng)典算法非常有價值,考試、裝逼、面試都十分有用。但現(xiàn)在是效率時代,編程講究生產(chǎn)效率,利用LINQ,可以讓程序猿避免寫一些基本算法,把精力花在業(yè)務(wù)處理上
    2012-02-02
  • .NET?Core?Web?APi類庫內(nèi)嵌運行的方法

    .NET?Core?Web?APi類庫內(nèi)嵌運行的方法

    這篇文章主要介紹了.NET?Core?Web?APi類庫內(nèi)嵌運行的方法,本節(jié)我們重點討論如何內(nèi)嵌運行.NET Core Web APi類庫,同時介紹了兩種激活比如控制器特性方案,需要的朋友可以參考下
    2022-09-09
  • .Net極限生產(chǎn)力之分表分庫全自動化Migrations?Code-First

    .Net極限生產(chǎn)力之分表分庫全自動化Migrations?Code-First

    這篇文章主要介紹了.Net極限生產(chǎn)力之分表分庫全自動化Migrations?Code-First,輕量級針對分表分庫讀寫分離的解決方案,具有零依賴、零學(xué)習(xí)成本、零業(yè)務(wù)代碼入侵適配
    2022-07-07
  • javascript判斷是否有對RadioButtonList選項選擇

    javascript判斷是否有對RadioButtonList選項選擇

    寫個Javascript來判斷是否有對RadioButtonList選項選擇,附動畫演示,感興趣的朋友可以了解下,希望對您們有幫助
    2013-01-01
  • LINQ to XML的編程基礎(chǔ)

    LINQ to XML的編程基礎(chǔ)

    本文介紹了LINQ to XML的編程基礎(chǔ),即System.Xml.Linq命名空間中的多個LINQ to XML類,這些類都是LINQ to XML的支持類,它們使得處理xml比使用其他的xml工具容易得多。在本文中,著重介紹的是XElement、XAttribute和XDocument。
    2010-02-02
  • ASP.NET對SQLServer的通用數(shù)據(jù)庫訪問類

    ASP.NET對SQLServer的通用數(shù)據(jù)庫訪問類

    這篇文章主要實現(xiàn)了ASP.NET對SQLServer的通用數(shù)據(jù)庫訪問類
    2016-02-02
  • ASP.NET Core利用Jaeger實現(xiàn)分布式追蹤詳解

    ASP.NET Core利用Jaeger實現(xiàn)分布式追蹤詳解

    這篇文章主要給大家介紹了關(guān)于ASP.NET Core利用Jaeger實現(xiàn)分布式追蹤的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用ASP.NET Core具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • WPF依賴屬性用法詳解

    WPF依賴屬性用法詳解

    本文詳細講解了WPF依賴屬性的用法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • MvcPager分頁控件使用注意事項

    MvcPager分頁控件使用注意事項

    這篇文章主要為大家詳細介紹了MvcPager分頁控件使用的注意事項,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • xUnit 編寫 ASP.NET Core 單元測試的方法

    xUnit 編寫 ASP.NET Core 單元測試的方法

    這篇文章主要介紹了xUnit 編寫 ASP.NET Core 單元測試的方法,文中代碼非常詳細,幫助大家更好的參考和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06

最新評論

彰化县| 华亭县| 紫阳县| 法库县| 微山县| 雅安市| 亳州市| 高阳县| 城市| 和平县| 个旧市| 紫云| 拉萨市| 新巴尔虎左旗| 蓬莱市| 拉萨市| 吉安县| 彭水| 廊坊市| 常山县| 遂川县| 宾阳县| 江陵县| 大厂| 含山县| 大安市| 和龙市| 沈阳市| 晋城| 德江县| 桃江县| 依兰县| 张北县| 清河县| 凌云县| 德钦县| 海伦市| 红河县| 法库县| 象州县| 平乡县|