iT邦幫忙

2021 iThome 鐵人賽

DAY 7
0

如何撰寫測試驗證例外 — ExpectedExcetption 與 Assert.Throws(delegate)

我們在撰寫商業邏輯時,能夠準確預期功能在什麼情況會產生例外也是一門學問;因此,在此段會探討驗證例外的寫法與歷史(來源可參考單元測試的藝術 2.6.2 節或 Marcus 文章的 NUnit 測試例外 Exception)。

在探討驗證例外之前,我們先再回顧 HelloBank 這隻商業邏輯專案的內容—存款功能,如下:

public void Add(double amount)
{
    if (amount < 0)
    {
        throw new ArgumentOutOfRangeException(nameof(amount));
    }

    balance += amount;
}

從此段程式碼,可以看出來當使用者存款的金額小於 0 元的時候,會發生 ArgumentOutOfRangeException。而在早期 NUnit 2 的時代,是採用一種寫法叫 [ExpectedExcetption] 的寫法,如下:

[Test]
[ExpectedExcetption(typeof(ArgumentOutOfRangeException))]
public void Adding_Negative_Funds_Throws()
{
    // Act
    account.Add(-500);
}

但在單元測試的藝術有提到該方法並非良好的方法,其原因為 [ExpectedExcetption] 的概念是告訴測試執行器,將這個功能放進 try-catch 的區塊中,找出該段程式碼的 Exception。這樣的風險可能會造成抓取出來的例外可能不是我們預期的例外(比如建構函式寫錯,拋出例外時造成測試未成功,進而導致誤判程式碼出錯原因)。另外,NUnit 3 已將此寫法刪除(換言之,這種寫法已經走入歷史了)。

在單元測試的藝術提供的寫法是利用 Assert.Catch(delegate),該方法會回傳例外的物件執行個體,進而對該物體驗證其正確性(比如抓取其中的 Message,並驗證是否有涵蓋我們預期的字串)。但在 NUnit 3 有提供另一種寫法,可以更簡潔地解決驗證例外,程式碼如下:

[Test]
public void Adding_Negative_Funds_Throws()
{
    // Act + Assert
    Assert.Throws<ArgumentOutOfRangeException>(() => account.Add(-500));
}

程式碼採用 Assert.Throws(delegate) 寫法,我們把原先 Act 的動作利用 Lambda 語法寫進委派中,所以可看到 Act 與 Assert 的程式碼寫在同一行,利用 Assert.Throws 驗證 Lambda 內的委派結果與泛型是同一種例外類別。

PS:若對 C# 不懂,T 是指泛型,而 delegate 是指委派(在此不解釋各自的細節,可參考能不能講一下什麼是泛型(Generics)老宅筆記本: .NET委派(delegate),寫得滿淺顯易懂的)。


單元測試的分類 — Category

該特性如標題,顧名思義就是指把測試指定你分類的名稱,程式碼如下:

[Test]
[Category("Exception Tests")]
public void Adding_Negative_Funds_Throws()
{
    // Act + Assert
    Assert.Throws<ArgumentOutOfRangeException>(() => account.Add(-500));
}

而透過 Windows Test Explorer 可看到做分類的特性,如圖:

https://ithelp.ithome.com.tw/upload/images/20210907/201273781evWdZTiiU.png

PS:尚未在 Visual Studio for Mac 看到相關的 UI 可以顯性特性(也可能是我沒找到),以及如何透過 Category 只跑相對應的測試,也會在之後花時間 Study 並補齊。


上一篇
Day 6-單元測試 NUnit 更多常用的特性-1 (基礎-5)
下一篇
Day 8-單元測試完善 HelloBank、基礎總結與核心技術概述 (基礎-7)
系列文
單元測試從入門到進階之路 (以 C# NUnit 3 X NSubstitute 為例)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言