閱讀554 返回首頁    go 阿裏雲 go 技術社區[雲棲]


《Cucumber:行為驅動開發指南》——2.8 讓測試通過

本節書摘來自異步社區《Cucumber:行為驅動開發指南》一書中的第2章,第2.8節,作者:【英】Matt Wynne , 【挪】Aslak Hellesy著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看

2.8 讓測試通過

既然已經有了可靠的失敗場景,那就是時候讓這個Cucumber場景指導我們編寫解決方案了。

有一個非常簡單的方案能讓測試通過,但該方案其實不會有實際的幫助,不管怎樣我們先試一下,哪怕為了好玩兒:

下載first_taste/08/calc.rb
print "4"

試試運行cucumber,你會看到場景最終通過了:

...

1 scenario (1 passed)
3 steps (3 passed)
0m0.025s

很好!不過這個方案有什麼問題呢?畢竟我們說過希望做能讓測試通過的最少的工作,對不對?

事實上,這與我們之前說的不完全一樣,我們說希望做能讓測試通過的最少的、有用的工作。這裏我們做的確實讓測試通過了,但並不十分有用,暫且不說它根本沒有計算器的功能這一事實,我們先看看這行耍小聰明的代碼在測試時漏掉了什麼。

  •  我們沒有嚐試從命令行讀取輸入。
  •  我們沒有嚐試做加法運算。 在《Crystal Clear:小團隊的敏捷開發方法》[Coc04]一書中,Alistair Cockburn提倡在項目中盡早構建一個可行走的骨架(walking skeleton),以便發現技術選型的任何潛在問題。顯然我們的計算器非常簡單,但一樣值得我們考慮一下這條原則:為什麼我們不構建一種能通過該場景的更有用的東西,並且讓它幫助我們更多地了解自己打算使用的實現呢?

如果你不能信服這種觀點,可以嚐試將這種解決方案看成一個代碼重複的問題。我們在兩個地方硬編碼了4這個值:一處是場景中,另一處是計算器程序中。在更複雜的係統中,類似的重複可能不會被注意到,因而使場景變得脆弱。

讓我們強迫自己修複這個問題,可以使用Kent Beck在《測試驅動開發》一書中所說的三角法(triangulation)。我們使用一個新的名為Scenario Outline(場景輪廓)的關鍵字來為特性添加另一個場景:

下載first_taste/09/features/adding.feature
Feature: Adding

Joe問:我覺得很怪異,你一直在讓測試通過但毫無作用!

我們實現了一個步驟,它調用了計算器程序然後就通過了,即便這個時候“計算器”還隻是一個空文件。這到底是怎麼回事?

記住一個步驟本身並不是一個測試,測試是整個場景,除非所有步驟都通過了,否則場景不可能通過。在我們實現所有步驟之後,隻有一種辦法能讓整個場景通過,那就是構建一個能運行加法運算的計算器!

像這樣由外向內工作的時候,我們常常會使用空計算器程序這樣的樁(stub),把它作為一個將來需要填充的預留區域。我們知道不可能永遠把空文件留在那裏並僥幸成功,因為最終Cucumber會告訴我們,要讓整個場景通過就必須回來給空文件夾添加內容,使它能做點有用的事。

故意隻做能讓測試通過的最少的、有用的工作,這一原則看起來很懶,但實際上是一條紀律,它能保證我們的測試徹底且周密:如果測試沒有驅動我們編寫正確的軟件,那麼我們就需要更好的測試。

Scenario Outline: Add two numbers 
 Given the input "<input>"

 When the calculator is run

 Then the output should be "<output>"

 Examples:
  | input | output | 
  | 2+2  | 4   | 
  | 98+1 | 99   |

我們把場景轉變成了場景輪廓,這使我們可以用表格指定多個場景。另一種方法是複製並粘貼原來的整個場景然後改變其中的一些值,但我們認為使用場景輪廓在表述實例方麵可讀性更強,並且我們想讓你體驗一下Gherkin語法允許的其他寫法。我們看一下現在輸出是什麼樣子:

$ cucumber

Feature: Adding

 Scenario Outline: Add two numbers   
  Given the input "<input>"      
  When the calculator is run      
  Then the output should be "<output>" 

  Examples: 
   | input | output |
   | 2+2  | 4    |
   | 98+1  | 99   |
   expected: "99"
      got: "4" (using ==) (RSpec::Expectations::ExpectationNotMetError)
   ./features/step_definitions/calculator_steps.rb:15
   features/adding.feature:6

Failing Scenarios:
cucumber features/adding.feature:3 # Scenario: Add two numbers
2 scenarios (1 failed, 1 passed)
6 steps (1 failed, 5 passed)
0m0.072s

從摘要中的 2 scenarios (1 failed, 1 passed),我們可以看到Cucumber已經運行了兩個場景,Cucumber運行場景輪廓的時候,它會把實例(Examples)表中的每一行擴展成一個場景。第一個實例(結果為4的那個)仍然通過了,但是第二個實例失敗了。

現在,肯定應該用一個更切實的解決方案重新實現我們的程序了:

下載first_taste/10/calc.rb
print eval(ARGV[0])

首先我們讀取命令行參數ARGV[0],然後把它傳給Ruby的eval方法。這足以算出與計算器輸入相關的結果,最後我們將結果打印到終端。

試一下,是不是兩個場景都通過了?很好!你已經構建了自己的第一個用Cucumber驅動的應用程序。

最後更新:2017-06-05 12:01:57

  上一篇:go  《Cucumber:行為驅動開發指南》——2.9 我們學到了什麼
  下一篇:go  《Cucumber:行為驅動開發指南》——2.7 添加一個斷言