前言
API 講解完後接下來我們來介紹能夠快速驗證自己程式邏輯的好用工具-單元測試(Unit-Test),實務上也有使用單元測試的開發方法,如:TDD(Teat-Driven Development)測試驅動開發;接下來介紹內容會以單元測試的藝術以及公司大神提供文件所學介紹,最後會以完成先前開發API單元測試為目標。
內文
單元測試
單元測試的藝術對一個優秀單元測試的定義為:
一個單元測試是一段自動化的程式碼,這段程式會呼叫被測試的工作單元,
之後對這個單元的單一最終結果的某些假設或期望進行驗證。
單元測試幾乎都是使用單元測試框架進行撰寫的。
撰寫單元測試很容易,執行起來快速。
單元測試可靠、易讀、並且很容易維護。
只要產品程式碼不發生變化,單元測試的執行結果是穩定一致的。
該具備的特性有:
特性 | 定義 |
---|---|
1、Fast(快速) | 每一個單元測試執行的速度夠快。 通常單一個單元測試要在毫秒之內完成。 |
2、Independent(獨立性) | 不能與外部資源相依。外部物件有:資料庫、服務、其他單元測試等。 |
3、Repeatable(可重複) | 單元測試要是可以重複執行的,其結果不會因為執行次數而改變。 |
4、Self-Validating(可反應驗證結果) | 單元測試執行的結果,不論成功或失敗都要能從測試報告內清楚明瞭原因。 |
5、Timely(及時) | 單元測試應該要在產品測試碼完成的當下就能驗證執行結果是否符合預期。 |
單元測試的3A原則:
原則 |
---|
1、Arrange : 初始化目標物件、相依物件、方法參數、預期結果,或是預期與相依物件的互動方式。 |
2、Act : 呼叫目標物件的方法。 |
3、Assert : 驗證是否符合預期。 |
整合測試
接下來介紹一下可能會混淆的整合測試。
單元測試的藝術對整合測試的定義為:
整合測試是對一個工作單元進行測試,而這個測試對被測試的單元並沒有完全的控制,
而是使用該單元一個或多個真實依賴的相依物件,例如時間、網路、資料庫等。
所以如果一個測試情境直接進入DB撈取資料,那他其實是整合測試,並不屬於單元測試。
測試驅動開發(Teat-Driven Development,TDD)
TDD是一種開發的模式,詳細的步驟可以參考下圖1-4(取自單元測試的藝術)。
可以看到 TDD 的步驟如下:
- 撰寫一個測試 Function。
- 執行測試,因為還沒實作要測試的目標,所以得到失敗結果。
- 撰寫剛好能通過測試的產品程式碼。
- 執行測試,成功撰寫下一個測試;失敗修正程式。
以此步驟作為循環不斷的重複。
優點是可以快速透過下面這些情境驗證程式:
- 如果一個測試失敗了,沒有經過修改她就再次運行成功了,你其實是在測試這個單元測試本身。
- 如果你預期一個測試應該失敗,但她卻成功了,那這個測試本身可能有缺陷,或是測試的物件不對。
- 如果一個測試之前失敗了,擬調整之後預期他會執行成功,但她依然是失敗的,那這個測試可能有缺陷,或是測試的期望結果不正確。
碎碎念分隔線:
當然這是理想情況下能夠進行 TDD,而真實自身經驗情況都是圖1-3,除了重要商業邏輯程式外,真的是有空再回來補測試,而且有的時候商業邏輯被翻盤了,舊的測試邏輯也不符合情境,一切都是浮雲。
練習
接下來我們就來練習寫一個簡單的單元測試。
首先建立一個單元測試的專案:
建完後我們會看到一個空的單元測試方法。
接下來我們需要建立一個簡單的程式範例讓我們做單元測試的練習。
我們建立一個類別庫專案。
現在我們的專案結構如下:
接著在 Class1.cs 內建立一個簡單的 Function
public string GetUserName(string name)
{
if(string.IsNullOrWhiteSpace(name))
{
return "請輸入使用者姓名!";
}
return $"Hi!{name},歡迎使用";
}
接著對 Class 點選右鍵建立單元測試。
開始寫我們的第一個單元測試
[TestMethod()]
//可以直接使用中文清楚表示要測試的規則
public void 當UserName為空值_應回傳提示訊息()
{
//arrange
var target = new Class1();
var name = string.Empty;
//act
var actual = target.GetUserName(name);
//assert
Assert.AreEqual("請輸入使用者姓名!",actual);
}
提醒:要記得打開測試總管!!
點選執行。
確認結果。
接下來補完我們的測試程式。
[TestMethod()]
public void 當UserName為Null_應回傳提示訊息()
{
//arrange
var target = new Class1();
string name = null;
//act
var actual = target.GetUserName(name);
//assert
Assert.AreEqual("請輸入使用者姓名!", actual);
}
[TestMethod()]
public void 當UserName不為空_應回傳正確訊息()
{
//arrange
var target = new Class1();
string name = "Sian";
//act
var actual = target.GetUserName(name);
//assert
Assert.AreEqual($"Hi!{ name},歡迎使用", actual);
}
確認結果。