TDD私有方法測還是不測

記錄和分享一個經典kata, 題目是如何打印一個鉆石型的字符。

Given a letter print a diamond starting with 'A'
with the supplied letter at the widest point.
 
For example: print-diamond 'E' prints

    A
   B B
  C   C
 D     D
E       E
 D     D
  C   C
   B B
    A

按照TDD的套路,從最簡單的開始,第一個開始 'A'。

     @Test
    public void Print_A_Test() {
        String[] expected = {"A"};
        String[] actual = DimondPrint.print('A');
         diamodAssert(expected, actual);
    }
    public static String[] print( char val) {
        return new String[] {"A"};
    }

接著第二個用例如下:

    @Test
    public void Print_B_Test() {    
        String[] expected = {           
             " A ",
             "B B",
             " A "
        };
        String[] actual = DimondPrint.print('B'); 
        diamodAssert(expected, actual);
    }
     public static String[] print( char val) {
    
        if( val ==  'B') {
        
            return new String[] {
                " A ",
                "B B",
                " A " 
             };
        }
        return new String[] {"A"};
    }

第三個測試用例就是,測試字符'C'

   @Test
    public void Print_C_Test() {
    
        String[] expected = {           
           
                "  A  ",
                " B B ",
                "C   C",
                " B B ",
                "  A  "
                };
                
        String[] actual = DimondPrint.print('C'); 
        diamodAssert(expected, actual);
    }

當時在做到這個時候,明顯感覺步伐太大,需要小步分解。
第一個思路就是可以將這個菱形分解成四個小正方形, 左上,右上,左下,右下,然后兩兩合并。這個就有一組方法.

String[] getLeftTopSquare(char c){...}
String[] getRightTopSquare(char c){...}
String[] getRightDownSquare(char c){...}
String[] getLeftDownSquare(char c){...} 
String[] mergeOnVertical(String[] top, String[] down){...}
String[] mergeOnHorizontal(String[] top, String[] down){...}

但是面臨的問題是:
如何用TDD驅動這些方法?陷入兩難選擇。

  1. 如果將這組方法作為一個私有方法,但是沒法很好的支持測試。
  • 如果當作公共接口去調用,問題是如果出錯,定位不準去。
  • 測試的細節(jié)穿透力不強
    通過共有接口或者方法,去測試后面的一個私有方法. 私有方法邏輯簡單問題不大, 如果這個私有方法比較復雜,就有隔靴搔癢。沒有直接測試私有方法那么給力。
直接測試 vs 間接測試
  1. 如果將這些方法,作為一個共有的方法。
  • 暴露出DiamondPrint 類的內部實現(xiàn)部分。
  • 第二使得不同層次的api暴露出來,抽象不統(tǒng)一,接口可讀性差。
  • 另外這些方法測測試與基于需求的測試用例混合在一起,是的需求不清晰。因為這個不是同一個層面的抽象放在一起,可讀性就會差很多。
    @Test
   public void Print_A_Test() {
       String[] expected = {"A"};
       String[] actual = DimondPrint.print('A');
        diamodAssert(expected, actual);
   }

  @Test
   public void Print_mergeOnVertical_Test() {
       String[] expected = {"A","B"};
       String[] actual = DimondPrint.mergeOnVertical("A", "B");
        diamodAssert(expected, actual);
   }

  1. 提取工具類。

將上面一組方法提取到一個抽象類,比如DiamondUtility; 然后對這個類用TDD來開發(fā)。然后在上面的類里面調用已經測試好的方法。也就是從下往上開發(fā)。好處也很明顯。

  • 直接測試,給力;
  • 測試反饋定位準確;
  • 測試代碼可讀性提升;
  • API的抽象層次統(tǒng)一。

其實還有很有爭議的兩個方法。

  1. test recycle。 直接修改測試用例,使得代碼和測試用例漸進演化,最終實現(xiàn)。自己感覺不推薦,中間的測試用例被刪除了,使得測試用例分解過程,以及如果后期代碼維護出錯反饋定位不準確???a target="_blank" rel="nofollow">代碼 和文章。

  2. 與3 相反,測試自頂向下;對于沒有實現(xiàn)的部分,先用hardcode,然后再逐步用代碼替換一部分; 這個其實思路和1類似,是基于對外的接口來測試私有方法。缺點同上,中間測試用例沒有,同樣后期維護不方便。

回到開始問題: 私有方法測試還是不測試?

簡單回答,NO! 私有方法要通過對外的接口來測試;如果私有方法復雜,提取出工具類去測試。

Note: 這個題目有很多種解法,下一篇來介紹。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評論 19 139
  • 文| 麻生生 儒家和道家,都是中國文化的主流。儒家塑造著國人的社會人格,道家則成就著國人的自然人格。道家的智慧,博...
    _Gloria_閱讀 899評論 16 6
  • 我們每個人都是普通人而已。 還記得小的時候,還是孩童的我總是騎在父親的頭上玩耍,嬉鬧。有什么委屈...
    唱歌的小孩紙閱讀 325評論 3 2
  • 冬去春來, 花落花開, 不知道啊, 多少鮮花等待此時, 不明白啊, 多少鮮花為此開, 花瓣飛, 飛躍,飛揚,飛飏。
    勵志決定成為漫畫家的人閱讀 195評論 0 2
  • 昨天是我唯一沒有下游戲幣的比賽,之前無論什么比賽我都會選擇一方,對比賽會有個整體的預測。也猜中了不少冷門,比如冰島...
    流殤夕水閱讀 375評論 0 0

友情鏈接更多精彩內容