iT邦幫忙

DAY 25
3

30天快速上手TDD系列 第 25

[Day 25]BDD - TDD from BDD

前兩篇文章介紹到了,為什麼需要BDD來輔助我們進行TDD,原因是需求、user story與acceptance test cases都是透過DSL來描述,這離最後要implement的程式碼還太遙遠,導致無法從驗收測試案例的描述,簡單的轉換到TDD的過程,這中間的gap太大。

上篇文章介紹的BDD工具是SpecFlow,也稍微介紹了如何安裝,以及其feature檔中feature與scenario描述的相關注意事項,及其與user story/acceptance test cases的對照。更帶到了如何透過scenario來定義清楚acceptance test cases,再從scenario定義出對應到Unit Testing的3A原則。

接下來這篇,就承接著上篇文章,用預設的feature與scenario,透過TDD的方式來完成一個加法器。

上一篇文章:[Day 24]BDD - SpecFlow Introduction
本系列文章專區
@TDD Start

SpecFlow 1.9.0 之前版本
第一步就先把原本的 Step 中內容刪掉,執行測試,將測試結果內容中的 Step 程式碼,放到 Step 中。執行時的錯誤訊息,如下圖所示:

將錯誤訊息中的提示,貼到Step檔後,如下圖所示:

上述這是SpecFlow 1.8版的建議方式,但1.9.0以後的版本,不用這麼麻煩了,接下來介紹1.9.0以後的版本,怎麼樣可以更快產生對應的step檔,而不需要先執行錯誤,再自行複製貼上。

SpecFlow 1.9.0 以後的版本
打開Feature檔,可以看到當Scenario中,若無對應的step描述,則會顯示出不同顏色,如下圖紫色的區塊:

若feature上仍有尚未定義的step,則點滑鼠右鍵,menu中就有「Generate Step Definition」的選項。

點選後Specflow會自動判斷,該feature檔上還有哪些尚未定義的step,就像VS2010自動產生單元測試案例一般的畫面,如下圖所示:

上面有兩個選項:

  1. Generate:可直接產生對應的step檔案到測試專案中
  2. Copy method to clipboard:將對應的step檔案內容,複製到剪貼簿

產生完Step檔之後,scenario的部份就會變成白色的了,如下圖所示:

這個檔案就會跟之前的版本一模模一樣樣。

@TDD的第一步
了解feature與scenario之後,我們的目標物件為Calculator。

針對 Feature , 建立我們的測試目標:Calculator。並透過 Visual Studio 的產生功能,直接幫我們產生對應的 class 到 AtmOperation 的 project 中。如下圖所示:

接著第一個 Given 為『輸入數字50到 calculator 』,這邊我們的設計,就是想辦法符合 Scenario 的 Step 就對了。所以針對 Calculator ,新增一個 FirstNumber 的屬性,並設定為50。如下圖所示:

接下來,第二個 Given 為『輸入70到 calculator 』,這邊新增一個SecondNumber的屬性,並設定為70。如下圖所示:

接下來,應該針對 When 來設計,[When(@"I press add")],當我按下 add 時,所以這邊為 Calculator 新增一個 Add 的方法。如下圖所示:

最後,針對 Then 來驗證結果。 Scenario 上寫的很清楚,結果應該為 120 。所以這邊為 Calculator 新增一個 Result 的屬性,並驗證其值是否為 120 。如下圖所示:

到這,我們幾乎只是一直在用Visual Studio內建的產生類別、屬性跟方法的功能,一點都不難吧。類別、屬性與方法的命名,也會完全符合scenario的情境與意義。

ok,我們針對 Calculator 加法的 Feature , 針對兩個數字的相加這個 Scenario ,已經寫完我們的測試程式了,執行一下測試吧!

碰!紅燈!放個煙火慶祝一下,我們已經進入 TDD 循環的第一個步驟:紅燈。寫一個一開始會執行失敗,但又符合測試目標物件行為的測試程式。

看一下詳細的測試結果資訊,可以發現兩個 Given 都是 done ,錯誤發生點是在 When I press add 。如下圖所示:

@在Scenario上偵錯
接下來,神奇的地方要來了,我們直接在 feature 檔上,scenario中的 When 部份加上中斷點。是的,你沒看錯,就是在 feature 檔案上新增中斷點。

接下來用偵錯測試的模式執行測試, When 的時候就會中斷,如下圖所示:

按下 F11 ,可以進去 Step 的程式中,如下圖所示:

再進去 Add 方法中, YES !! 總算看到我們的 production code 了,Add 方法中,還沒有實作相關的內容,所以測試會拋出 exception 。如下圖所示:

接下來,我們要想辦法,滿足 Scenario 的需求,當 FirstNumber 為 50 ,而 SecondNumber 為 70 時, Result 結果應該是 120 。

所以 Add 的方法內容,要滿足這個需求,我們做了以下的設計:

看起來很 ok ,接下來再執行一次測試,可以看到測試結果是綠燈了!而且,在詳細的測試訊息中,可以在『標準主控台輸出』中,看到 Scenario 的執行結果,測試程式就像說故事一樣,表達了 Calculator 的一種行為。如下圖所示:

到這邊,我們已經先使用 BDD 來描述物件行為,並自動產生 feature 中, Scenario 對應的測試程式。接下來透過 TDD 的方式,來執行測試與開發實際的程式。

@小結
或許,您會覺得目前這樣的程式,很沒有彈性,如果需要再新增第三個數字,第四個數字,該怎麼辦?您可以有兩個方式:

  1. 重構 Calculator ,但重構過程中,仍須滿足已經存在的測試程式。
  2. 等真的有該需求出現時,再來滿足需求後,重構程式。

重構的部份,相信讀者朋友們經過前面一系列的洗禮,應該可以駕輕就熟了。如果想複習一下的朋友,請參考前面 Day9~Day19 的文章。

筆者的心得是:
原本練習 TDD 時,總覺得 test cases 不夠精準,無法呈現 domain 的行為,而 QA 或 PM 所設計的 test cases ,又無法與測試程式作結合。

BDD 把最艱困的一個阻礙點打通了,目標物件的行為,可以透過 Feature 來與 User Story 或 Use Case 結合,透過 Scenario 來產生測試程式的外框與繫結,可以讓測試程式就像在描述 Scenario 般一樣自然。

整個概念有點類似下圖所示:

註:嚴格來說,上圖應該加上ATDD的stage,會更為清楚。不過這邊僅當示意簡圖。

下一篇文章,我們會為BDD做個總結,讓讀者朋友可更清楚的了解BDD在整個開發流程中的定位。


上一篇
[Day 24]BDD - SpecFlow Introduction
下一篇
[Day 26]User Story/ATDD/BDD/TDD - 總結
系列文
30天快速上手TDD31
0
ted99tw
iT邦高手 1 級 ‧ 2012-11-02 19:58:13

讚讚讚

除了灑花按推,更要努力偷偷學起來才行...

衝刺衝刺衝刺

0
pajace2001
iT邦研究生 1 級 ‧ 2012-11-06 21:24:10

我在 Generate Step Definition 時,的確有看到四個 method

但是 Generate 出來的 .cs 只有三個,好像有兩個被合併了!

I have entered 50 into the calculator 和 Given I have entered 70 into the
calculator 合併成 I have entered (.*) into the calculator

<pre class="c" name="code">
[Given(@"I have entered (.*) into the calculator")]
public void GivenIHaveEnteredIntoTheCalculator(int p0) {
    ScenarioContext.Current.Pending();
}

這時候是要手動複製一個嗎?還是可以有其他的做法呢?
我問題怎麼這麼多啊XDOrz

就是91 iT邦研究生 4 級 ‧ 2012-11-06 21:30:06 檢舉

不用手動複製啊,在SpecFlow裡面,預設會幫你用regular expression,把相同scenario的,透過參數來取代。(這是為了避免同樣的function重複產生)

如果你真的不想透過regular expression來合併參數,那再generate那邊有個checkbox,取消就好了。

pajace2001 iT邦研究生 1 級 ‧ 2012-11-06 21:33:57 檢舉

原來如此~~~我太粗心了

pajace2001 iT邦研究生 1 級 ‧ 2012-11-06 21:57:49 檢舉


Geberate 旁邊沒有 checkbox Orz

0
pajace2001
iT邦研究生 1 級 ‧ 2012-11-06 21:33:13

hatelove提到:
看一下詳細的測試結果資訊,可以發現兩個 Given 都是 done

可是我的不是 done, 而是出現 binding error.... 疑惑

就是91 iT邦研究生 4 級 ‧ 2012-11-06 21:44:21 檢舉

針對scenario偵錯一下吧 :)

pajace2001 iT邦研究生 1 級 ‧ 2012-11-06 22:04:14 檢舉

原來會出現 binding error 是因為我手動複製(複製 GivenIHaveEnteredIntoTheCalculator)的結果,雖然不能兩個,我後來是不手動複製,只有一個而已~就可以做出一樣的結果了(done)

0
pajace2001
iT邦研究生 1 級 ‧ 2012-11-06 21:44:47

hatelove提到:
按下 F11 ,可以進去 Step 的程式中,如下圖所示

又一個問題 (sorry, 我好煩喔~~)
在 Visual studio 2012 中,UnitTestProject 如果直接按F11他會出現以下訊息

A project with an Output Type of Class Library cannot be started directly. In order to debug this project, add an executable....(等等)

之前是可以在 test case 中下中斷點,然後 TEST -> Run -> All tests 來執行,並且中斷點也有效。可是這個方式在這裡 Scenario 好像不管用 ,是不是有什麼地方我忽略掉了呢?

感謝加菲貓大大~~~謝謝謝謝謝謝

看更多先前的回應...收起先前的回應...
pajace2001 iT邦研究生 1 級 ‧ 2012-11-06 21:45:44 檢舉

可以了XD

pajace2001 iT邦研究生 1 級 ‧ 2012-11-06 21:47:16 檢舉

好神奇阿~我先在 test case 下斷點,之後他就停在我先前下的斷點~
接著我再把 test case 斷點取消,他還是可以停在 scenario 這個斷點~~
好神奇阿~~終於又跨了一步了~
謝謝謝謝謝謝

pajace2001 iT邦研究生 1 級 ‧ 2012-11-06 21:50:06 檢舉

原來是要用 Ctrl + D, A 他才會停~~~
以前都沒注意到這點~~~~~

就是91 iT邦研究生 4 級 ‧ 2012-11-06 22:05:18 檢舉

VS2012 跑SpecFlow 1.9.0跟1.9.1 應該有bug唷。

specflow的forum上有被提出來,也有被fix了,但我印象中還沒有release fix完成的版本出來。所以建議您如果碰到問題,就還是先用VS2010會比較好一些 Orz

就是91 iT邦研究生 4 級 ‧ 2012-11-06 22:06:30 檢舉

要偵錯Scenario,只需要在Scenario上的某一句下中斷點,接著滑鼠右鍵,應該就有Debug Scenario可以選了。

0
就是91
iT邦研究生 4 級 ‧ 2012-11-06 22:10:01

by the way, 真的很高興,有讀者真的願意跟著文章練習 :)

也很感謝你的feedback,那可能代表文章哪邊講的不夠清楚。不過因為篇幅有限,真的很難完全介紹完,所以還是得K一點官方的document或sample,會比較容易瞭解囉 XD

我要留言

立即登入留言