跳到主要內容

[TDD之路] 隔離的單元測試

寫程式常常會有很多難以隔離的邏輯,這邊舉一個關於時間的例子。

如果要你寫一個判斷是不是聖誕節的簡單程式你會怎麼寫?

        public bool IsTodayXmas()
        {
            var today = DateTime.Today;
            if (today.Month == 12 && today.Day == 16)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

.
上面的邏輯正確且簡單,唯一的缺點是不好測試。為什麼呢?
試著寫一段 Unit Test 看看,你可能會像下面這樣寫

        [TestMethod]
        public void TodayIsXmas()
        {
            var checker = new XmasChecker();
            var result = checker.IsTodayXmas();
            Assert.AreEqual(true, result);
        }

.
這個測試這樣寫的話,只有在聖誕節當天才會 Pass.
所以困難的地方在於怎麼把變動的邏輯給隔離開來。

下面提供幾個作法,在不影響已發佈的使用下來讓程式可以測次,各有優缺點
首先都是先將 DateTime.Today; 這個邏輯提取方法 GetToday(),然後

  1. 透過新的建構子
  2. 透過新的屬性
  3. 透過新的方法
  4. 使用繼承,變更 GetToday() 的存取範圍為 Protected virtual
大概是這幾種方法,前三種作法都差不多,GetToday() 邏輯如下
        private DateTime? _today = null;
        private DateTime GetToday()
        {
            return _today ?? DateTime.Today;
        }

.
透過建構子,屬性,或是新的Set的方法來改變這個 private 變數 _today.
然後在隔離出來的 GetToday() 中判斷 _today 是否有被設定過值,如果有就直接回傳 _today,如果沒有就回傳 DateTime.Today。
.
這三種方法的缺點是這些都是為了測試而新增的方法或屬性,或許會被不知情的使用者誤用。那有沒有不新加功能的辦法呢? 有的,那就是透過繼承與覆寫。
.
首先也是將DateTime.Today; 這個邏輯提取方法 GetToday()
        protected virtual DateTime GetToday()
        {
            return DateTime.Today;
        }
.
差異是關鍵字 virtual ,這個關鍵字代表可以讓子類別覆寫。
因此在測試專案中,只要寫一個 FakeXmasChecker 繼承 XmasChecker 然後覆寫GetToday()
然後直接在覆寫的方法中回傳需要的時間即可。
如下面的方法所示
        protected override DateTime GetToday()
        {
            return new DateTime(2017, 12, 25);
        }
.

留言

這個網誌中的熱門文章

加密貨幣交易實戰心得筆記

加密貨幣交易實戰心得筆記 . 對於加密貨幣,雖然公司有個團隊已經在開發相關產品,但我自己只有大概了解什麼是加密貨幣,什麼是比特幣,以及什麼是區塊鍊。雖然稍微知道,但也只是知道,並沒有真的去購買跟投資。 . 幾天前公司舉辦了一場課程,邀請了史旺基到公司分享加密貨幣的交易實戰。課程需要自費,但其中包含了直接幫我們購買比特幣,並將購買的比特幣交易給我們。可以實際接觸到加密貨幣的交易讓我很期待,因此毫不猶豫的就參加了這堂課程。 . 這堂課程並不是在技術上來跟你說什麼是加密貨幣或是區塊鍊的技術是什麼,它著重在由淺入深的介紹什麼是比特幣、什麼是區塊鍊、什麼是去中心化、什麼是挖礦、誰是中本聰、什麼是以太坊以及以太幣、什麼是熱錢包以及冷錢包,等等這類的相關資訊。 . 學習並了解上面介紹的基本資訊之後,課程的重點放在了交易所的介紹與操作上面。我們一步一步的申請了台灣的兩個交易所,分別是 MaiCoin 以及 BitoEX。相信有在投資比特幣的人應該都已經知道,但對於沒有追上潮流的我來說,這個資訊真的是省了我很多研究的時間,立刻感覺前進了一大步,雖然手續費高常常可能卡幣,但中文介面,簡單的認證與交易方式,讓我感覺已經真的觸碰到了比特幣與區塊鍊的邊。 . 除了台灣交易所,更有國際交易平台的介紹與教學,這邊我就不一一介紹了,因為我自己也都還沒申請,而且這些國際平台很多是停止申請帳號的。 . 另外還有更多的資訊,包括怎麼開始投資,投資心法以及不少的中英文介紹資料,包括App的介紹。 . 這堂課除了讓我立刻從門外漢大躍進成初心者,更是直接開始打怪(購買)了,破除了這個最大靜摩擦力之後,我讓我的投資標的又多了一個可能,感覺非常值得。

Multiple without multication or addition operator

Given two binary strings, return their sum (also a binary string). For example, a = "1101" // 13 b = "1000" // 8 Return “1101000”. // 104 Solution: implement Binary add to perform multication static int MultipleWithoutOperator(int num, int multiplier) { StringBuilder sb = new StringBuilder(); string binary = Convert.ToString(num, 2); string binaryMultiplier = Convert.ToString(multiplier, 2); string temp = ""; for (int i = binaryMultiplier.Length-1, j=0;i >= 0;i--,j++){ if (binaryMultiplier[i]=='1') { if (string.IsNullOrEmpty(temp)) { temp = binary.PadRight(binary.Length + j, '0'); } else { temp = BinaryAdd(temp, binary.PadRight(binary.Length + j, '0')); } } } return Convert.ToInt32(temp, 2); } static string BinaryAdd(string a, string b) { int carryover = 0; Stri...

ReSharper For VS C# 常用功能概觀介紹

因為目前任職的公司有幫員工購買 ReSharper (R#) 的授權,所以才第一次接觸到這個工具。一開始卡卡的,但是目前已經使用了快三年,覺得如果沒有這個工具就好像電動牙刷沒有電一樣 XD。所以本著好東西要跟別人分享的心態來寫一下目前使用的心得。 ReSharper 的主要功能如下 程式碼檢查,自動重構,快速導航和編碼協助等等的功能。 個人認為 ReSharper 最重要的功能就是提供編碼協助的功能,透過 Alt +  Enter 就可以快速一步一步的把程式碼"生"出來。這也是主要加速開發的主要原因,透過從使用端來 Generate 出產品程式碼,把關注點放在需求上面而非程式碼上。 再來就是自動重構的功能,例如 Extract Method, Introduce Field, Inline Variable. 等等的功能,讓你重構的時候很可以安心重構不用擔心改壞程式碼原本的行為。且很簡單使用,增加重構程式碼的意願。且還有 Ctrl + Shift + R 這個萬解的快捷鍵,可輕鬆入門。 程式碼檢查功能算是那種好像不是最重要的功能,但是少了他又不方便的功能。它可以幫你找出那些程式碼並沒有被用過,哪種寫法可以更好,拼字錯誤,命名大小寫錯誤之類的。 快速導航功能在追 Code 的時候非常好用,Ctrl + T 可以全專案找尋所有的型別、成員,快速定位,快捷鍵 Alt + \ 可以快速定位到目前檔案的成員上面,Ctrl + , 找最近檔案,Shift + Ctrl + , 可以找最近編輯檔案,快又有效且都有搜尋過濾功能。 其他還有很多沒有提到的功能例如 Live template, Code Cleanup 之類的功能也是很好用,之後有時間再慢慢介紹瞜~ 附上一些連結讓大家參考看看 官方介紹影片 VS C# 熱鍵對應表 ReSharper的好處(開發者,產品經理,商業) ReSharper的主要特性