【Unit Test】Day 5 - 透過InternalsVisibleTo來達成單元測試的外部注入
Demo檔案 : Git傳送門 請參照UnitTest_Day5的Branch延續昨日的進度,我們將呼叫API的RestSharp獨立出來,並且用依賴介面及外部注入的方式將IRestSharp注入到PTX來達成隔離,並且做到可測試性。
但面臨令一個問題,如果今天開發的是共用套件類的專案,這樣變成要使用物件都必須知道該用什麼東西注入才可使用,這往往會造成使用者困擾,封裝性也不佳,因外部注入的IRestSharp是每個人都可以另外實作的。 甚至更深一層去想,究竟IRestSharp是否需要用Public讓外部使用者都知道有這個東西呢? 是不是反而因為要達到可測試性而讓封裝這件事做得更差?
來看看另一種方式
假設我認為使用這個套件的人只要簡單的建立PTX後即可使用,至於內部如何呼叫API的實作使用者並不需要關心,那麼我們先將IRestSharp從建構子拿掉吧,並且做一個專門產生IRestSharp實體的Factory來滿足需求。
撰寫IRestSharpFactory
/// <summary> /// 製作IRestSharp的工廠 /// </summary> internal class IRestSharpFactory { //這邊特別注意存取修飾子是用Internal //原因是我並不希望專案之外的人使用且知道有這東西 //而internal剛好能滿足這需求 internal static IRestSharp Generate() { //產生實體 return new MyRestSharp(); } }
接著修改原本的PTX.cs
public class PTX { IRestSharp _MyRestSharp { get { //這邊改成用工廠建立MyRestSharp實體 return IRestSharpFactory.Generate(); } } /// <summary> /// Construct /// </summary> public PTX() { //建構子參數移除 } 以下省略..... }
這邊馬上面臨到一個問題,那我們怎麼Mock IRestSharp,昨天是放在建構子中並透過Nsubstitute來Mock
![]() |
封裝性變好了,但也變得難以介入模擬外部行為
|
從IRestSharpFactory著手吧!!
想辦法讓IRestSharpFactory可以讓我們注入Mock的假物件
/// <summary> /// 製作IRestSharp的工廠 /// </summary> internal class IRestSharpFactory { /// <summary> /// 此屬性只供UnitTest注入 /// </summary> internal static IRestSharp _IRestSharpForUnitTest; internal static IRestSharp Generate() { //如果這個值不為Null,則表示單元測試所注入,直接回傳 if (_IRestSharpForUnitTest != null) { return _IRestSharpForUnitTest; } //產生實體 return new MyRestSharp(); } }
這邊開了一個_IRestSharpForUnitTest屬性,讓外部能夠注入它,接著在Generate的方法中判斷,如果當_IRestSharpForUnitTest不為Null時,直接回傳(通常會特別在這個屬性寫上說明僅供單元測試使用,正常Production Code禁止使用!!)
想辦法在單元測試中注入_IRestSharpForUnitTest
你可能會發現在單元測試中看不到IRestSharpFactory....
原因是我們宣告成Internal,如果要能在專案之外看到就只能開成Public了,但回到最一開始討論的,不就是為了封裝才把他宣告成Internal嗎?如果又改回Public那我們這段工不就白費了,還好還有別的方法可以達成。
告訴UnitTestDay3這個專案,除了它自己之外,還有誰能看到它宣告成Internal的類別與屬性方法
讓我們先打開UnitTestDay3專案的AssemblyInfo
寫下這行
InternalsVisibleTo這邊是要填AssemblyName,透過這個Attribute告訴UnitTestDay3這個專案還有誰能看到它內部的Internal。
而AssemblyName怎麼看呢?在專案上右鍵 > 屬性
如果你有很多單元測試專案需要能看到,InternalsVisibleTo是可以很多組的。
接著在單元測試中就可以看到啦
這樣就達成我們想封裝起來的需求,卻也能讓單元測試進行注入,那今天就談到這吧!!
0 意見:
張貼留言