iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0
Software Development

.NET Core與React組合開發技系列 第 26

.NET Core與React組合開發技_第26天_C#單元測試介紹與常用框架

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20221007/20107452MUp4zQDaRr.png

/images/emoticon/emoticon13.gif

1.測試的種類

軟體測試一般分4階段:
1.單元測試:對軟體中的最小可驗證單元進行檢查和驗證。各個程式獨
立單元會與其他單元隔離。
優點:盡早發現Bug、較利於重構、需要的測試環境和情境前置準備較單純
缺點:增加開發人員的工作量、學習門檻及時間成本較高、沒辦法找出跨模組時期才會出現的Bug

2.整合測試:軟體功能單元依據設計需求規格,組裝成模組、(子)系統的
過程中各部分工作是否有成功達到要求。
優點:較能驗證到模組間銜接、參數互傳的功能是否穩定
缺點:
每次都要重Build運行花費的時間太久(比較多重複性動作)
需要的測試環境和情境前置準備較為繁雜

3.系統測試:在所有單元、整合測試後,對系統的功能及效能的總體測試。在此階段測試不僅僅包括軟體本身,還包括電腦硬體及其相關的周邊裝置、實際執行時大批量資料、非正常操作(如資安攻擊)等。通常包括壓力測試、容量測試、效能測試、安全測試、容錯測試….等。

4.驗收測試(交付測試):針對使用者需求、業務流程進行的測試,以確定系統是否滿足驗收標準,由使用者、客戶或其他授權機構決定是否接受系統。

2.單元測試框架的定義

單元測試框架 (Unit Test Framework)
讓開發人員可以輕易地撰寫以「類 (Class)」為單位的測試程式,並且隨時可以執行自動化的重複性測試 (automation repeatable test),以確保該單一類別的正確性。

3.撰寫單元測試的目的與效益
(必須老實說普遍公司都不太會願意導入寫單元測試,大部分會重視寫新功能或者BUG修復。)

目的:
1.能快速發現既有的某段程式碼邏輯是否因需求修改增加而有被變動。
2.減少重複性的測試前置動作
3.自動化測試原先所有測試案例,節省人工手動重複測試的耗時。
Unit Test:
Tiny testable parts of a program independently tested for expected functionality.
TDD(Test-Driven Development):
Process that uses unit tests to drive the design of software.

人工手動測試(未導入單元(自動化)測試時傳統驗證作業流程)
每次要驗證某一頁網站表單程式當中的某一個function或event邏輯
都要**不停重複執行某些前置動作 **
=>Launch App
=>Login
=>Navigate
=>Fill out Form
=>Submit
=>Verify the result

軟體修復調整成本與時間關係
https://ithelp.ithome.com.tw/upload/images/20221007/20107452fnrOkuz7i7.png

Ref:https://devmethodologies.blogspot.com/2013/10/change.html

手動測試(未導自動化單元測試)vs單元(自動化)測試
情境:
某個Function因為不同時間點演進而增減改某些code過去撰寫的背景規則不可考
通常習慣只針對新需求的Output做驗證而可能忽略以前的規格會不會因為新的一次更改而導致舊的需求又無法work只符合新的需求。
在我電腦上跑可以過怎麼在你電腦上跑就壞?

導入單元測試優點:
會明確留下過去的需求規格在測試程式中,且會自動把所有test case再次測試。
可讓開發者在需求異動情境維護成本降至最低。
新增功能時較不用擔心改壞以前的程式。
讓我們能自動每次功能更新都去不間斷的自動Review Code。

4.較好的撰寫單元測試原則
一個測試只測一件事情、一個方法,以一個邏輯為單位。
Unit Test本身應不具備邏輯(if… else if…else,switch , loop…)。
測試案例之間不應該有相依性,而應該各自獨立。
不和外部資源(DB,WebService,web api,檔案系統…)相關聯,通常又被稱作「隔離測試」(Ex:即便在離線環境也要能夠測試跟api呼叫或DB存取有關的unit test)
F.I.R.S.T 原則
3A原則(Arrange , Act , Assert)

F.I.R.S.T 原則

Fast:測試執行的速度要夠快。
Independent:單元測試之間各自互不影響,不會 因為測試A失敗而影響測試B。
Repeatable:測試應能在任何環境下都能夠成功重複執行。
Self-Validation:測試結果的輸出,能讓人分辨哪些測試通過與沒通過。
Timely:撰寫測試要及時,最好是在產品開發前期就先寫(TDD的概念)

(PS:Test-Driven Development)

3A原則

Arrange:初始化目標物件、相依物件、方法參數、預期結果
Act:呼叫目標物件的方法
Assert:驗證是否符合預期(預期結果跟Act返回實際結果是否吻合)

寫單元測試的時機點
以既有系統而言:
1.經常有需求異動的功能
2.經常出現錯誤的function
3.極為複雜的邏輯
4.通常會針對public修飾的 method做測試

不適合寫單元測試的情況
以既有系統而言:
1.和DB有相關存取
2.和檔案系統有相關存取
3.和Call WebService , Web API , ASHX
4.有要在特定實體機器上綁定driver的操作或call一些特定環境指令(linux)

都較適合直接把時間投入在整合測試
也有一派專門研究怎麼去針對這些外部資源寫替身物件(也就是之後延伸出Test Double,Fake之類的派別)

5.主流測試框架的使用
以下都是在vs2019 IDE (community)測試操作
https://ithelp.ithome.com.tw/upload/images/20221007/201074523wdw6slXBU.png
MSTest(MSTest2.0)

Visual Studo內建的單元測試工具(對VS IDE整合性最佳)
自動產生測試程式相關框架
不限Class Library的專案才可以測試

Supported platforms:
.NET 4.5.0+ .NET Core 1.0+ (Universal Windows Apps 10+, DNX Core 5+) - ASP.NET Core 1.0+
MIT License
https://www.nuget.org/packages/MSTest.TestFramework/2.1.1/license

MSTest單元測試專案建立(.NET Framework)

假如目前你有一個現有的專案隸屬在某方案之下
Step1.可針對方案=>右鍵=>新增專案=>選擇「單元測試專案(.NET Framework)」
有一個很像酒精燒杯圖示的
https://ithelp.ithome.com.tw/upload/images/20221007/20107452NPXFTQoKGo.png
選定好放置目錄跟專案名稱後按建立
https://ithelp.ithome.com.tw/upload/images/20221007/20107452iqAxzYYYVA.png

就可以看到自己剛創建好的單元測試專案
https://ithelp.ithome.com.tw/upload/images/20221007/20107452AD4zrRZgRK.png

MSTest單元測試專案建立(.NET Core)

選擇「MSTest測試專案」

https://ithelp.ithome.com.tw/upload/images/20221007/2010745213mUZEiXTx.png

預設選擇以.Net Core版本為主

https://ithelp.ithome.com.tw/upload/images/20221007/20107452oAJvdjzsf5.png

開啟Test Explorer
從檢視下拉點選開來或透過快捷組合鍵Ctrl+E , T
https://ithelp.ithome.com.tw/upload/images/20221007/20107452s833qjJ2PE.png

https://ithelp.ithome.com.tw/upload/images/20221007/20107452iPkjFMMGud.png

Test Explorer裡面跟方案類似一樣可包含多個不同測試專案並可自行選擇要一次全執行還是只針對特定測試專案做執行

https://ithelp.ithome.com.tw/upload/images/20221007/20107452oKCNDVsIXD.png

MSTest執行測試
(TestClass/TestMethod)
預設MSTest專案會有所謂的TestClass跟TestMethod兩種annotation
TestClass就是將一個類別標記成測試類別,TestMethod則一樣是標記成測試方法的意思。
這裡假設我們就是直接要來驗證程式主進入點Main要輸出的結果為”Hello World”
https://ithelp.ithome.com.tw/upload/images/20221007/201074529yXthlELv8.png

https://ithelp.ithome.com.tw/upload/images/20221007/20107452znCnjEvS89.png

(AreEqual/AreNotEqual)
比較常見的就是用於測試實際運行結果(actual)是否跟預期的輸出or回傳值(Expected)一致
在MSTest透過Assert.AreEqual(Expected, result);來進行
https://ithelp.ithome.com.tw/upload/images/20221007/20107452Rg4LUcc2vz.png

除了一致也提供不一致的查檢method
https://ithelp.ithome.com.tw/upload/images/20221007/20107452l3zMd5TcBC.png

MSTest偵錯測試

(AreEqual/AreSame差異)

Assert.AreEqual(Expected, result); 單純只針對內容、值的比對
Assert.AreSame(Expected, result); 指兩個物件是否為相同的物件(同一塊記憶體位址)

https://ithelp.ithome.com.tw/upload/images/20221007/20107452leX8qTR0KH.png

在前面增加一段指向到Expected物件的程式
就又通過測試result = Expected;//Copy the reference into result.
這裡執行Mstest的偵錯測試來看過程差異
https://ithelp.ithome.com.tw/upload/images/20221007/2010745268hxSqBynf.png

https://ithelp.ithome.com.tw/upload/images/20221007/20107452gqtsIzFqDI.png
可以到在執行到多加的指向同一Expected物件語句之前
兩個memory位置是不同的
https://ithelp.ithome.com.tw/upload/images/20221007/20107452CetzxM2Lcn.png

MSTest的Assert執行流程

可以在一個TestMethod中使用多次Assert相關測試API(比如AreEqual),
但只要前方有任一個API測試比對失敗,緊接在後的都不繼續執行下去。(不建議這樣寫)

https://ithelp.ithome.com.tw/upload/images/20221007/20107452XSDnZuZjPy.png

單一值得測試比對

兩值是否相同
Assert.AreEqual(object expected, object actual)
Assert.AreNotEqual(object expected, object actual)

兩址是否相同
Assert.AreSame(object expected, object actual)
Assert.AreNotSame(object expected, object actual)

Boolean比對
Assert.IsTrue(bool condition)
Assert.IsFalse(bool condition)

Null比對
Assert.IsNull(object value)
Assert.IsNotNull(object value)

字串類比對
StringAssert.Contains(string value, string substring)
StringAssert.StartsWith(string value, string substring)

正規表示式比對
StringAssert.Matches(string value, Regex regex)
StringAssert.DoesNotMatch(string value, Regex regex)

特定某型別比對
Assert.IsNotInstanceOfType(object value, Type type)

集合內容的測試比對

兩集合是否元素及總數皆相同(元素的順序要相同)
CollectionAssert.AreEqual(ICollection expected, ICollection actual)
CollectionAssert.AreNotEqual(ICollection expected, ICollection actual)
兩集合是否元素及總數皆相同(元素的順序不用相同)
CollectionAssert.AreEquivalent(ICollection expected, ICollection actual)
CollectionAssert.AreNotEquivalent(ICollection expected, ICollection actual)
集合A是否為集合B的子集合
CollectionAssert.IsSubsetOf(ICollection subset, ICollection superset)
CollectionAssert.IsNotSubsetOf(ICollection subset, ICollection superset)

該集合中是否都為特定某型別
CollectionAssert.AllItemsAreInstancesOfType(ICollection collection, Type expectedType)
該集合中是否都非Null
CollectionAssert.AllItemsAreNotNull(ICollection collection)
該集合中是否都為唯一值
CollectionAssert.AllItemsAreUnique(ICollection collection)
該集合是否包含特定某一元素
CollectionAssert.Contains(ICollection collection, object element)
CollectionAssert.DoesNotContain(ICollection collection, object element)

在既有專案中新增單元測試
到既有專案的受測程式區域(某個class)右鍵建立單元測試

https://ithelp.ithome.com.tw/upload/images/20221007/20107452q1fPP3jSVZ.png

必須是public修飾的class,method才可建立測試。

https://ithelp.ithome.com.tw/upload/images/20221007/20107452rf2RnE2Jma.png

https://ithelp.ithome.com.tw/upload/images/20221007/20107452Zgxw512LyV.png

https://ithelp.ithome.com.tw/upload/images/20221007/20107452iiYowRRp3J.png

https://ithelp.ithome.com.tw/upload/images/20221007/201074526ZFRiXAdZ1.png

https://ithelp.ithome.com.tw/upload/images/20221007/20107452RIUT1WY8eU.png

其餘更深入有關於
虛設常式(stub)跟模擬物件(mock)、假物件(Fake)
可再參考blog介紹
https://coolmandiary.blogspot.com/2021/09/01.html


上一篇
.NET Core與React組合開發技_第25天_重構加入至購物車的程式
下一篇
.NET Core與React組合開發技_第27天_新增添加購物車單元測試與導入session機制
系列文
.NET Core與React組合開發技30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言