嗯…… 好久沒有寫文章,再次寫文章的題目卻讓人搞不太清楚,簡單來說就是看下面圖會比較清楚,
不要問為何會有這樣的程式,又為何要這麼樣設計與使用,那個不是重點,重點在於怎麼去對這一段程式去做測試。
計算兩點座標距離的程式在 GeographyService 的 ValidateDistance 方法裡,
介面:IGeographyService
實作:GeographyService
如果兩點座標距離超過 20000 公尺,就會拋出 InvalidOperationException 例外,不超過的話則是把計算後的距離放到 out distance 參數當中。
這裡的計算兩個座標點的距離會使用到 System.Device 參考,然後 GeoCoordinate 類別的擴充方法 GetDistanceTo() 的命名空間則是在 System.Device.Location,
MSDN - System.Device.Location 命名空間 ()
MSDN - GeoCoordinate.GetDistanceTo 方法 (System.Device.Location)
而 SampleContext 類別的 FooMethod 方法會使用 GeographyService 的 ValidateDistance() 方法,
主要是測試 SampleContext.FooMethod 對於兩個座標點計算距離之後的處理,對於原本 GeographyService.ValidateDistance() 方法的實作內容並不是目前要測試的主要目標,所以這邊就會使用 NSubstitute 來建立 IGeoprahpyService 的 Stub 物件。
下面的寫法看起來沒有什麼問題,
而且測試也會過
但是實際上因為沒有真正的執行到 GeographyService.ValidateDistance() 實作裡,所以不會真的去計算兩個座標點的距離,所以上面的測試所使用到的 distance 都一直是零(int 的初始值)。
怎麼測?
問題來了,一個 void 修飾方法是不會有回傳值,而且把值給傳遞到使用端的是透過 out 參數,這樣的情況要怎麼在單元測試方法裡用 NSubstitute 去完成測試呢?
直接看 NSubstitute 的文件,會用到以下的兩篇文件裡的方式,
NSubstitute: Callbacks, void calls and When..Do
NSubstitute: Setting out and ref args
將原本的方法依據上面兩篇文件說明的方式做了修改。因為是修飾詞為 void 的不回傳值的方法,所以也無法使用 Returns(),但是有個 out 參數要把計算後的距離給傳遞出來,所以就使用了 When … Do… 方法,然後在 Do… 這裡 out 參數要傳遞出來的值。
大家對於上面 Do… 裡面的 x[4] 會有點質疑,為什麼是用「4」呢?
其實那個「4」所指的是方法簽章裡的參數索引數,由零開始算,而 ValidateDistance() 方法簽章的索引位置為四的就是 out int distance 這個參數。
如果方法簽章裡有多個 out 或是 ref 參數也是使用相同的做法,可以指定多個參數,不過要指定好參數的索引位置。
以偵錯模式進入單元測試裡,實際去看看測試執行的時候是不是就是真如我們所指定的,out int distance 是傳遞指定的「500」?
進入偵錯模式之後可以觀察到 out distance 參數的確是使用我們再單ˋ原測試裡所指定的 500.
其他針對不同 distance 決定不同的 message 情境也使用相同的情境一併完成單元測試,
看起來這邊好像都已經把這邊的使用情境都測試到了,不過還是有一個部分忘記測了,那就是兩個座標點位置的距離如果超過 20000m 的時候就會拋出例外,這個部分還是需要被測試到,至於怎麼測這個例外呢?
其實做法跟這一篇所講的是差不多,只是有一點點不同,不過這個部分就下一篇再來說吧。
參考連結
MSDN - System.Device.Location 命名空間 ()
MSDN - GeoCoordinate.GetDistanceTo 方法 (System.Device.Location)
NSubstitute: Callbacks, void calls and When..Do
NSubstitute: Setting out and ref args
NSubstitute完全手册索引 - Dennis Gao - 博客园
[C#.NET] 單元測試 Mock Framework - NSubstitute - 余小章 @ 大內殿堂- 點部落
想要更加瞭解測試與敏捷開發,就一定要關注 91 哥的「91 敏捷開發之路」Facebook 粉絲專頁
https://www.facebook.com/91agile
以上
Cash 哥, 太客氣了
回覆刪除