天天看點

VS2010 學習筆記 TDD (4) 重整代碼(一)

我們都已經發現,前3節我們雖然建立了SimpleStack類,也實作了IsEmpty屬性和Push方法,也通過了測試。但毫無疑問,這完全不合常理。那這節開始,我們要進入三部曲的重整代碼階段。所謂重整,就是将最簡單能使測試通過的代碼,加入必要的代碼,以達到實際所需功能,同時也能讓測試通過。

任務 1 – 将精力從讓測試通過轉移到完成功能上

  • 我們需要真正将一個對象推入到棧中,并實際改變了棧,即在推入對象後,棧應當儲存這個對象,棧就應該不為空棧(IsEmpty等于false)。那怎麼去測試呢?Push後驗證IsEmpty 是否為false就行了:

[TestMethod]

public void ThenShouldBeAbleToPushAnItemOntoTheStack()

{

    var theStack = new SimpleStack();

    theStack.Push(1);

    Assert.IsFalse(theStack.IsEmpty);

}

  • 運作這個測試,應該不會通過。為什麼失敗呢?
    • 别忘了,我們之前為了讓測試通過,隻是簡單将IsEmpty實作為隻讀的永遠傳回true的屬性。現在就要考慮如何讓IsEmpty按實際情況來傳回真實的數值,也展現出Push方法帶來的效果。
    • 測試驅動開發同時也被稱為測試驅動設計 ,就是基于我們即将要看到的這些原因,我們正在定義開發的系統應當有什麼行為和怎麼去設計它,用重複方法來表現系統行為。
  • 打開SimpleStack類,我們坐下來思考一下這個類。棧應該可以提供儲存某些狀态的機制,特别是它現在儲存何種條目的狀态。 
  • 将條目儲存在一個清單中,我們就可以檢查清單的大小來确定棧的IsEmpty值。清單也提供了儲存推入的條目的地方。

class SimpleStack

{

    ArrayList _items ;

    public bool IsEmpty

    {

        get { return _items.Count == 0; }

    }

    internal void Push(int p)

    {

        _items.Add(0);

    }

}

  • 注意ArrayList 類型未被識别,利用CTRL+. ,輸入System.Collections 命名空間。
  • 運作所有的測試。還是失敗!為什麼?測試結果給出的原因是ArrayList未被初始化。
  • 添加預設的構造方法,并初始化清單

class SimpleStack

{

    ArrayList _items;

    public SimpleStack()

    {

        _items = new ArrayList();

    }

    …

}

  • 再次運作測試,這時候應該全部通過!(綠色)
  • 但問題來了,我們怎麼知道Push方法存入正确的對象呢?就如我們上面的代碼,Push方法隻是将零 (0)加入到清單中。
  • 是以,我們的測試方法就要繼續做進一步的測試驗證,同時也要添加新的功能(方法)。
  • 添加一個新的測試,使之可以驗證推入一個對象後,能夠拉出這個對象,并確定它就是我們剛剛推入的對象:

[TestMethod]

public void ThenShouldBeAbleToPushAndPopAnItemFromTheStack ()

{

    var theStack = new SimpleStack();

    theStack.Push(1);

    int poppedItem = theStack.Pop();

    Assert.AreEqual(1, poppedItem);

}

  • 再次提示Pop 方法不存在,我們使用Smart Tag幫忙建立新的方法,并利用Quick Search(CTRL+,) 定位到此方法
  • 注意VS已确定Pop方法需要傳回一個值,并且知道傳回值的類型,真牛!

internal int Pop()

{

    throw new NotImplementedException();

}

  • 運作測試方法,會失敗并提示NotImplementedException 意外。我們添加代碼使之可以通過測試:

internal int Pop()

{

    int value = (int) _items[0];

    _items.RemoveAt(0);

    return value;

}

  • 再次運作測試,還是失敗。為什麼呢?因為Assert使用AreEqual 方法來驗證推入的資料和拉出的資料是否一樣,結果在Push方法的實作代碼中,我們錯寫了Add(0) 。回到Push方法,将代碼改為:

internal void Push(int p)

{

    _items.Add(p );

}

  • 再運作測試,所有測試應該成功!

注意:我們現在不是深入讨論TDD的原理和規範上,也不是學習如何正确地實作一個棧類。

但是我們可以繼續設計和建立SimpleStack類,比如思考Pop方法調用在空棧上會出現什麼問題,還有如果嘗試操作一個滿棧的時候會出現什麼情況等等。

為了完成這些設計問題,我們需要建立更多新的測試方式,完成更多的測試方法。

同時,我們也可能留意到這個類存在一個明顯的bug,對于棧應該是先入後出(FILO),但Pop方法永遠都是從開頭拉出對象。那就要繼續設計測試方法來确定Push進入的資料就是Pop出來的資料。

繼續閱讀