只有累積,沒有奇蹟

2019年3月21日 星期四

[UnitTest] 如何測試目標方法中 Guid 型別的代碼 ?

情境
如果要產生一個亂數時很常會想到 Guid 方法解決,在 C# 使用 Guid 的方式相當簡單僅要透過  Guid.NewGuid  靜態方法產生一組 Guid 使用,在目前公司很常看到使用 Guid 作為識別碼,今天在重構舊代碼時忽然想到如果遇到 Guid 該如何進行加上單元測試,以下就目前想到的解法進行測試與說明,如果各位高手們有更好的方法歡迎高抬貴手一起討論研究。

解決方案
寫個簡單的 Sample 方法讓整個情境可以更容易了解,舉個例子來說有個 Generator 類別提供 NewGuidToken 方法產生 Guid 資料並回傳給呼叫端,Sample Code 如下
public static class Generator
{
    public static Guid NewGuidToken()
    {
        return Guid.NewGuid();
    }
}
第一時間讓我想到之前上 TDD 遇到測試今天是不是聖誕節案例時很像,但特別為了 Guid 寫一個介面讓使用的 class 實做,在透過建構子注入就可以斷開其依賴關係,但這 case 算是很單純個人覺得沒必要做這麼複雜的工,忽然想到在 C# 中每個資料型別物件大多都提供  TryParse  進行轉換,且該方法回傳結果為 true / fales bool型別,與 UnitTest 中的 Assert 搭配使用相當方便,單元測試 Sample Code 如下
[TestFixture()]
public class GeneratorTests
{
    [Test()]
    public void Input_NewGuid_Return_True()
    {
        // act 
        var input = Generator.NewGuidToken();

        // assert
        Assert.IsTrue(Guid.TryParse(input.ToString(), out Guid output));
    }
    [TestCase("Teset123")]
    [TestCase("Marcus")]
    public void Input_FakeGuid_Return_True(string input)
    {
        Assert.IsFalse(Guid.TryParse(input, out Guid output));
    }
} 
當你的情境只需要驗證產生出來的是否符合 Guid 時,就可以直接透過  Assert.IsTrue(your guid string)   來確認 Guid 格式是否正確 (第 11 行 );反之,如果要驗證格不符合時透過不是時用 Guid.TryParse + Assert.IsFalse 即可 ( 第17行 ),相當容易上手且閱讀性很高。

接著在來確認單元測試後的結果,其單元測試結果都執行正常
三份測試都通過且驗證無誤,綠燈 Pass 測試成功 !!

Summary
以上就是針對 Guid 型別寫單元測試的方法,也是小弟的矬見,如果各位大大有更好的方式歡迎一起討論跟溝通 :)


2019年3月20日 星期三

[VisualStudio] .NET 分析測試代碼覆蓋率 AxoCover

前言 
最近在替既有專案補上單元測試,除了在 SonarQube 可以看到測試代碼覆蓋率之外,這幾天同事推薦一套可以在 Visual Studio 執行的程式碼覆蓋率分析工具 AxoCover,可運行在 .NET 環境且開源免費,簡單玩了一下覺得十分不錯推薦給大家,今天就來分享 AxoCover 在 Visual Studio 2017 的安裝及基本操作說明。

安裝 AxoCover 
Step 1 : 選擇 Tools > Extension and Updates
Step 2 : 搜尋 AxoCover > 點擊 AxoCover > 安裝
Step 3 : 安裝完畢之後,重新啟動 Visual Studio > Tools > Extension and Updates 
發現 AxoCover 已安裝完成

AxoCover 使用說明 
在安裝完畢之後,開啟之前上課的測試專案 AxoCover 是如何進行分析跟介紹,預設是不會開啟 AxoCover 視窗,要到 Visual Studio > Tools > AxoCover 開啟,開啟後位置會在右邊視窗看到其 Logo
在開啟後會去讀取該專案是否有 UnitTest 單元測試項目
如果發現該專案沒有代碼時會跳出以下畫面,這畫面也會列出支援的 Framework,如 MSTest、NUnit、xUnit
接著會列出目前專案中所有的單元測試
上面區塊為 AxoCover 功能列,主要功能有以下

TEST
呈現目前既有的單元測試代碼,以及 UnitTest 相關的一些數字資訊,例如成功/失敗的測試案例數量,包含多少個類別、涵蓋專案中 Namespace 數字等資訊

RUN 
根據所選擇的區域執行單元測試,執行時 output 視窗畫面如下
Test execution started.

       ___
      /   \
      |   |
      \   /
      /   \
     /     \
 ___/       \___
/               \
|    _______    |
\___/       \___/

AxoCover Test Runner Console
(c) Peter Major 2017

> Executing tests...
| Runner version is 1.1.389.0.
| We are on x86 platform.
| File redirection is enabled for the following files:
| c:\users\marcustung\appdata\local\microsoft\visualstudio\15.0_3d91008b\extensions\wfz4mp4u.i0u\MSTestAdapter\Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.dll
| c:\users\marcustung\appdata\local\microsoft\visualstudio\15.0_3d91008b\extensions\wfz4mp4u.i0u\MSTestAdapter\Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.dll
| c:\users\marcustung\appdata\local\microsoft\visualstudio\15.0_3d91008b\extensions\wfz4mp4u.i0u\MSTestAdapter\Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.dll
| c:\users\marcustung\appdata\local\microsoft\visualstudio\15.0_3d91008b\extensions\wfz4mp4u.i0u\MSTestAdapter\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
| c:\users\marcustung\appdata\local\microsoft\visualstudio\15.0_3d91008b\extensions\wfz4mp4u.i0u\MSTestAdapter\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
| Setting up file redirection hooks...
| File redirection hooks are enabled.
>> Loading assembly from c:\users\marcustung\appdata\local\microsoft\visualstudio\15.0_3d91008b\extensions\wfz4mp4u.i0u\MSTestAdapter\Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.dll...
|| Loaded executor: Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestExecutor
<< Assembly loaded.
>> Running executor: Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestExecutor...
|| Passed   AssertionSamples.AssertExceptionSample.Divide_positive
   Failed   AssertionSamples.AssertExceptionSample.Divide_Zero
   Failed   AssertionSamples.AssertionSamples.CompareComposedCustomer
   Failed   AssertionSamples.AssertionSamples.CompareCustomer
   Failed   AssertionSamples.AssertionSamples.CompareCustomerList
   Failed   AssertionSamples.AssertionSamples.PartialCompare_Customer_Birthday_And_Order_Price
<< Executor finished.
| File redirection rules are cleared.
< Test execution finished.
Shutting down...
Exiting...
   SerializableException: 因為執行緒結束或應用程式要求,所以已中止 I/O 操作。
      於 System.ServiceModel.Channels.SocketConnection.HandleReceiveAsyncCompleted()
Test execution finished.

COVER
會先執行單元測試,跑完單元測試數據後會分析其覆蓋率資訊,Output 資訊前面與 run 相同省略僅列出後面不同的部分,可以看到分別進行測試代碼與相對應 class、Method、Point與 Branch 數字資料,並計算其總數與有單元測試代碼的百分比數字
< Test execution finished.
Shutting down...
Exiting...
Generating coverage report...

Committing...
Visited Classes 4 of 4 (100)
Visited Methods 11 of 13 (84.62)
Visited Points 37 of 47 (78.72)
Visited Branches 13 of 15 (86.67)

==== Alternative Results (includes all methods including those without corresponding source) ====
Alternative Visited Classes 4 of 10 (40)
Alternative Visited Methods 11 of 22 (50)
Test execution finished.  

REPORT
光看簡單數字相信一定無法滿足,這時分析完 COVER 之後可以點選 REPORT,會更清楚的將剛剛 Output 顯示文字資訊顯示出來,說明剛剛所點選的單元測試其涵蓋率是多少、多少沒有涵蓋、總數與其占比各自的數字為多少,可以說是相當的清楚讓你知道單元測試的資訊與透明度。

SETTING
設定項目則是提供想要設定的功能(廢話?),舉例來說在 Visualization 就可以選擇是否要看 line coverage、exception、Branch coverage、Partial coverager 或是 Test ahchors 等資訊;或是當跑測試時平台是 x86 或是 x64,都可以在設定區域找到,其設定詳細說明都可以參考官網介紹。

心得
一開始分析時在自己的電腦環境不管怎麼分析都是 100 %,但同事怎麼跑都是正常的,覺得非常不可思議(沒寫 code 就 100%),後來經過追根究柢後發現自己電腦的 output 訊息與別人都不同,異常時訊息如下
< Test execution finished.
Shutting down...
Exiting...
Generating coverage report...
Committing...
No results, this could be for a number of reasons. The most common reasons are:
    1) missing PDBs for the assemblies that match the filter please review the
    output file and refer to the Usage guide (Usage.rtf) about filters.
    2) the profiler may not be registered correctly, please refer to the Usage
    guide and the -register switch.
Test execution finished. 
訊息中提到有可能是未產生 PDB 檔案因此無法進行分析,恍然大悟將 VS 執行模式要選擇 DEBUG 立馬正常,終於解決別人都可以我不行的窘境,提供給有跟我一樣困擾的人思考方向,希望可以省下解決這簡單問題的時間 XD。

參考
AxoCover

2019年3月19日 星期二

[IIS] IIS 站台服務異常中止 - HttpEvent

問題
今天同事反應測試主機 IIS Server 無法使用,進到 QA 主機後發現所有的 IIS 服務都已停止,第一直覺就是到事件檢視器查看是否有異常的 Log 資訊,發現事件檢視器紀錄其中來源  HttpEvent  嫌疑重大,以下就針對解決此問題的方式做說明,若有問題歡迎提出一起討論或是給予指導。

解決方案
由於公司測試機對外預設都是以 80 port 為主,無故發生異常是蠻很奇怪,過去經驗如果 IIS 異常終止都會在事件檢視器有紀錄,因此第一步是先到事件檢視器查看是否有蛛絲馬跡,其中來源  HttpEvent  時間與異常時間很接近,其詳細錯誤訊息為 '無法為 [::]:80 繫結到其下的傳輸。IP 只聆聽清單可能包含了到不存在於此電腦介面上的參照。資料欄包含了錯誤數目"  ,從錯誤尋息來看有很大可能是 80 port 遭到佔用而影響到 IIS 服務啟動失敗;接下來是確認目前誰搶走了對外的 80 port,步驟如下

使用 netstat
在 windows 中可以下  netstat  指令查看目前是哪一個 process 在使用指定的 port,使用方式如下
PS D:\> netstat -ano | findstr 0.0:80
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       4
可以查看到目前 80 port 是被 processID [4] 佔用,接著我們可以在工作管理員找到 PID 的資訊

工作管理員
開啟 task manager ,切換到詳細服務 tab,根據 PID 排序即可看到 PID 為 4 的 process 為何,當時 debug 狀況發現 NGINX 服務佔用 80 port
處理方式也相當簡單,就兩種方式

服務 : 如果是服務(Service),當下立即到 Service 將 NGINX 停止服務;
執行 : 如果是某個執行檔,可以在 process 按下右鍵,選擇結束工作即可

操作方式如下
在強制停止 NGINX 服務之後,在重啟IIS 即可正常執行

工作管理員 - 開啟欄位
在工作管理員中可以開啟欄位的設定,一般來說我會特別開 PID、命令列等欄位,PID 是為了瞭解目前執行緒的號碼;命令列是拿來分辨 IIS 的執行 w3wp.exe 執行站台為何 (w3wp.exe - testPool,也就是執行檔加上站台Name),其餘就看自己的需求而定,操作方式透過 gif 呈現如下

後記
後來在追原因發現該 Server 在一早有重啟,可能是機器重新啟動時 NGINX 服務一起來就佔用 80 Port,因此 IIS 後續就無法正常使用,由於目前 NGINX 架設上已不須使用,因此還是建議將其服務砍掉避免之後此問題再次發生 :)

參考
80 通訊埠 被佔用(Port 80 required is already in use)解決辦法

2019年3月18日 星期一

[.NETCore] 'IWebHostBuilder' does not contain a definition for 'ConfigureKestrel' and no accessible extension method 'ConfigureKestrel'

問題
Kestrel web server 是一個輕量級的 Web Server 服務,同事求救在實作 How to use Kestrel in ASP.NET Core apps 其中的 Kestrel option 的 ConfigureKestrel 設定時發生錯誤,顯示不支援 ConfigureKestrel 方法簽章,以下就針對解決此問題的方式說簡單說明,若有問題歡迎提出一起討論或是給予指導。

解決方案
錯誤訊息文字為 : 'IWebHostBuilder' does not contain a definition for 'ConfigureKestrel' and no accessible extension method 'ConfigureKestrel' accepting a first argument of type 'IWebHostBuilder' could be found (are you missing a using directive or an assembly reference?)"  
在確認 從 ASP.NET Core 2.1 至 2.2 移轉 線上文件提到, 2.2 版開始 Kestrel Web Server 設定有所調整,原因是為了避免衝突 IIS 同處理序主控模型,忽然間恍然大悟發現是版本更新造成,下列先列出兩個不同版本所用的 API 簽章差異

ASP.NET Core 2.1
在 .NET Core 2.1 中要設定 Kestrel Web Server 設定的話要用  UseKestrel  方法,使用方式如下
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .UseKestrel(options =>
        {
            options.Limits.MaxConcurrentConnections = 100;
        });

ASP.NET Core 2.2
在 .NET Core 2.2 中要設定 Kestrel option 則需要使用  ConfigureKestrel  方法,使用方式如下
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureKestrel((context, options) =>
        {
            // Set properties and call methods on options
        });

確認 ASP.NET Core 版本
兩個版本使用方式不同,因此第一步是確認目前同事Visual Studio 使用的 target Framwork 版本為何,可以再專案按右鍵,點選屬性,得知目前使用版本為 2.1 且沒有並未安裝新版 

下載 .NET Core 2.2
安裝傳送門 : 請點我 
點選下載 .NET Core SDK & Runtime,接著進行安裝其安裝檔,無止盡點擊進行下一步

設定 Target Framework
下載完畢 ASP.NET Core 2.2 SDK & Runtime 之後,來確認在  Microsoft.AspNetCore.Hosting  namespace 底下是否有 ConfigureKestrel 方法
/// <summary>
/// Configures Kestrel options but does not register an IServer. See <see cref="M:Microsoft.AspNetCore.Hosting.WebHostBuilderKestrelExtensions.UseKestrel(Microsoft.AspNetCore.Hosting.IWebHostBuilder)" />.
/// </summary>
/// <param name="hostBuilder">
/// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure.
/// </param>
/// <param name="configureOptions">A callback to configure Kestrel options.</param>
/// <returns>The Microsoft.AspNetCore.Hosting.IWebHostBuilder.</returns>
public static IWebHostBuilder ConfigureKestrel(this IWebHostBuilder hostBuilder, Action<WebHostBuilderContext, KestrelServerOptions> configureOptions)
{
  if (configureOptions == null)
    throw new ArgumentNullException(nameof (configureOptions));
  return hostBuilder.ConfigureServices((Action<WebHostBuilderContext, IServiceCollection>) ((context, services) => services.Configure<KestrelServerOptions>((Action<KestrelServerOptions>) (options => configureOptions(context, options)))));
}
確定有其方法,重新至專案調整 target Framework 為 2.2 版,在重新建置專案後即可正常 Build 成功,成功解決,打完收工 ! 

後記
在 ASP.NET Core 推行速度相當快,在練習以及查詢網路資料時得先確定方法是否是舊的 API 與應用,才可以避免下次踩到相同地雷,MSDN 官網文章也有提到各版本移轉時的說明,詳細可以參考看 從 ASP.NET Core 2.1 至 2.2 移轉,或許下次從 2.2 升級到 3.0 或更新版本問題時可以先看一下版本升級說明也可以找到答案 :)

參考
從 ASP.NET Core 2.1 至 2.2 移轉

Copyright © m@rcus 學習筆記 | Powered by Blogger

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com