2022年1月22日 星期六

單元測試的藝術 - Chapter 2.3 驗證預期的例外

其實在這個主題之前,書中還有介紹SetUp與TearDown,

但因作者強烈不建議使用,因此我就直接跳過了。

直接來看怎麼驗證Exception。

使用[ExpectedException]

一開始作者先介紹最原始的方法,

使用[ExpectedException]去捕捉整個測試方法的Exception,

但實際使用時,似乎已經不支援了,

我的版本是3.13.2.0,作者提供的範例是2.6.0.12051。

不支援的原因,我想是因為使用[ExpectedException]去測試Exception,

等同是將IsValidFileName_EmptyFileName_ThrowException()包進一個很大的Try-Catch區塊,

即使你已經限制你要捕捉的Exception是ArgumentException,

但你並不能保證剛好是你期望的那一行程式碼所丟出的Exception,

假設你在測試方法中,一開始建立物件時呼叫了建構子,就拋出了這樣的例外,

那這個測試方法就通過了,但是卻沒有測到你想測試的function。

使用Assert.Catch<T>(delegate)

因此後續NUnit提供了Assert.Catch<T>(delegate)去捕捉Exception,如下所示:

由於Assert.Catch參數需求是delegate,因此這邊用了Lambda將想測試的function傳入,

此時如果捕捉到Exception便會將Exception物件回傳出來,

這時可以透過StringAssert.Contain()來驗證Exception物件內的資訊,

作者特別說明了StringAssert.Contain()的好處,

由於StringAssert.Contain()是檢查該字串內是否有你預期的資訊,並不需要完全相等,

因此在日漸增加的功能或修改之後(該回傳字串可能還會添加其他資訊),

StringAssert.Contain()依舊可以只比對你想比對的字串是否存在就好,

不必因為增加資訊而需要修改這個測試案例,讓測試更好維護。

測試撰寫完之後,馬上來執行看看:

居然失敗了!?

回頭檢查一下產品程式碼IsValidLogFileName(),

原來是我很自然地把後面新增的程式碼直接按照順序寫在原本的判斷條件後面了,

所以第一個判斷條件因為不等於.SLF當然就直接return false阿!

在這個時候完全體會到測試程式的存在意義了!

自己的認知是"這麼簡單的程式碼,應該不會出錯吧?"

但是卻真的出錯了,可以讓測試階段就查出錯誤,

不至於讓編譯通過,實際運作測試時才發現錯誤,

尤其當產品程式很龐大的時候,又或者需要搭配一些硬體設備才能測試的時候才去debug,

難度就會增加許多,不管是程式執行到這一行的流程繁瑣,或者硬體設備很難臨時借的到。

修改一下判斷條件的順序,執行測試。


成功了!

沒有留言:

張貼留言

社會新鮮人如何投資?

我的觀點是,在 沒有很多 本錢 的情況下, 別寄望每個月幾千元放到股票或者最近很夯的高股息ETF就能讓你致富, 先投資自己,讓自己的本業收入提高吧。