跳到主要內容

[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的介紹。 . 這堂課除了讓我立刻從門外漢大躍進成初心者,更是直接開始打怪(購買)了,破除了這個最大靜摩擦力之後,我讓我的投資標的又多了一個可能,感覺非常值得。

.NET 5.0 筆記

.NET 5.0 上線啦! 這次帶來什麼樣的改變呢? .NET 5.0 的前一版是 .NET Core 3.1。 等等,為什麼不是 .NET 4.x 呢? 難道歪果仁也不喜歡 4 這個數字嗎? 當然不是,這是因為 4.x 很容易跟 .NET Framework 4.x 搞混,造成搜尋上的麻煩。 不過這只是其中一個理由,另一個理由是因為想把 Core 這個詞拿掉,原因是 .NET 5 是接下來的主要實作平台,其支援比 .NET Core 以及 .NET Framework 還要更多類型的應用程式或是更多的平台。 至於 ASP.NET Core 5 還是會有的! 是以 .NET 5 為基礎的核心實作。保留 Core 這個字 就是為了與 ASP.NET MVC 5 作區別 (他們總算了解之前查資料有多困難XD),同樣的 Entity Framework Core 5.0 也會保留 Core 來跟 Entity Framework 5/6 作區別。 還有幾點是蠻重要的,.NET 5 做為未來的主要實作,但並不會取代 .NET Framework 4.x,.NET Framework 4.x 仍然會繼續支援。不過 Web Forms 技術將不會有轉移到 .NET 5 的計畫,取而代之的是有替代方案,例如 Blazor 或是 Razor page。 接下來讓我們期待 .NET 6.0 的登場吧! 畢竟這才是下一個 LTS 的版本阿!~