http://pythonhosted.org/lettuce/
介紹
親們!看到TDD/BDD 一定會感覺高階大氣上檔次,不是我們普通弔民玩的,最的近在一直在摸索自動化測試。也想體驗並引入BDD 低調奢華的內涵。於是,在網路上搜尋資料;話說這玩藝兒真的不太好理解,尤其對於沒有豐富程式設計的經驗的同學。
學習BDD ruby 的cucumber 是個不錯的選擇,但我是python 流的,自然找了來它的兄弟lettuce ,從官方版本(v0.1rc11)來看確實夠年輕的,不過由ruby 的cucumber 在前面開路,lettuce 應該會發展的很順利。
lettuce 除了官方文件外,幾乎找不到其它資料,為了理解lettuce ,我們不妨多去看看cucumber 的資料。
lettuce是一個非常有用的和迷人的BDD(行為驅動開發)工具。Python專案的自動化測試,它可以執行純文字的功能描述,就像ruby語言的cucumber。
lettuce,使開發和測試過程變得很容易,可擴充套件性,可讀性和-什麼是最好的-它允許我們用自然語言去描述個一個系統的行為,你不能想象這些描述可以自動測試你的系統。
安裝
請確認你已經安裝了python 以及pip安裝包管理工具。
不管是windows 還是linux 環境,進入pip目錄,只需下面一個命令就可以安裝lettuce .
user@machine:~$ [sudo] pip install lettuce
例子(階乘)
下面就通過官網的例子來領略lettuce的風騷。
什麼階乘?
0!=1
1!=1
2!=2×1=2
3!=3×2×1=6
....
10!=10×9×8×7×6×5×4×3×2×1=3628800
.....
下面是用python 語言的兩種階乘實現:
#coding=utf-8 #迴圈實現 def f(n): c = 1 for i in range(n): i=i+1 c=c*i return c #遞迴實現 def f2(n): if n > 1: return n*f2(n-1) else: return 1 #呼叫方法 print f(10) print f2(10)
OK!介於我們理解上面階乘的基礎上,來看看BDD是如何實現的。
lettuce 解析
建立以下目錄結構:
.../tests/features/zero.feature
/steps.py
現在我們來編寫zero.feature 檔案的內容
Feature: Compute factorial
In order to play with Lettuce
As beginners
We'll implement factorial
Scenario: Factorial of 0
Given I have the number 0
When I compute its factorial
Then I see the number 1
基於E文不好的同學,我這裡簡單翻譯一下:
功能:計算階乘
為了使用lettuce
作為初學者
我們將實現階乘
場景:0的階乘
假定我有數字0
當我計算它的階乘
然後,我看到了1
是不是很自然的描述?!第一段功能介紹,我要實現什麼功能;第二段場景,也可以看做是一條測試用例,當我輸入什麼資料時,程式應該返回給我什麼資料。
雖然是自然語言,但還是有語法規則的,不然一千個人有一千中描述,程式以什麼樣的規則去匹配呢?
其實它的語法規則非常簡單就幾個關鍵字,記住他們的含義及作用即可。
----------------------------------------------
- Feature(功能)
- Scenario(情景)
- Given(給定)
- And(和)
- When(當)
- Then(則)
----------------------------------------------
他們的含義與原有自動化測試框架的概念相似,類比如下:
關於feature檔案的作用,執行以及語法規則將在下一節中詳細介紹,這一節主要先來體驗luttuce的風騷。
有了上面zero.feature檔案的行為做指導,下面開啟steps.py 檔案來編寫我們的程式。
from lettuce import * @step('I have the number (\d+)') def have_the_number(step, number): world.number = int(number) @step('I compute its factorial') def compute_its_fatorial(step): world.number = factorial(world.number) @step('I see the number (\d+)') def check_number(step, expected): expected = int(expected) assert world.number == expected, \ "Got %d" % world.number def factorial(number): number = int(number) if (number == 0) or (number == 1): return 1 else: return number
我擦!咋一看怎麼跟我上面實現階乘的程式碼相差甚遠呀!不知道你和你的小夥伴有沒有驚呆!?好吧,以我拙劣的python語言水平試著來分析一下,這是啥?這是啥?這又是啥?
from lettuce import *
引入lettuce 下面的所有包
@step('I have the number (\d+)')
@step 字面意思是步驟
I have the number (\d+) 對應的就是zero.feature檔案中的第六句:Given I have the number 0
(\d+) 是一個正規表示式,\d 表示匹配一個數字,+ 表示匹配的數字至少有一個或多個。關於這個可以參考其他python 正規表示式的資料。
第一步:
@step('I have the number (\d+)') def have_the_number(step, number): world.number = int(number)
定義一個方法have_the_number,把假設的輸入(0)轉換成整型放入world.number中。
第二步:
@step('I compute its factorial') def compute_its_fatorial(step): world.number = factorial(world.number)
把have_the_number方法中world.number的變數值(0)放入 factorial() 方法中,並把結果返再賦值給world.number變數。
I compute its factorial 對應的就是zero.feature檔案中的第七句:When I compute its factorial
第三步:
def factorial(number): number = int(number) if (number == 0) or (number == 1): return 1 else: return number
這個是factorial()方法被呼叫時的處理過程,對引數的內容轉換成整數,判斷如果等於0或1的話就直接返回1,否則返回具體的數。(處理結果給了第三步的world.number)
第四步:
@step('I see the number (\d+)') def check_number(step, expected): expected = int(expected) assert world.number == expected, \ "Got %d" % world.number
expected 獲取的是zero.feature檔案中預期結果, 與第三步處理的實際結果(world.number)進行比較;assert 函式進行斷言結果是否正確。
I see the number (\d+)對應的就是zero.feature檔案中的第八句:Then I see the number 1
執行
切換到tests目錄下,執行lettuce 命令:
fnngj@fnngj-H24X:~/python/lettuce/tests$ lettuce
執行結果如下:
執行結果很清晰,首先是zero.feature檔案裡功能描述(feature),然後場景(scenario)每一步所對應steps.py 檔案裡的哪一行程式碼。
最後給出執行結果:
Feature(1 passed) 一個功能通過
Scenario(1 passed) 一個場景通過
Steps(3 passed) 三個步驟通過
完善
下面我們可以在zero.feature 中多加幾個場景(測試用例):
Feature: Compute factorial
In order to play with Lettuce
As beginners
We'll implement factorial
Scenario: Factorial of 0
Given I have the number 0
When I compute its factorial
Then I see the number 1
Scenario: Factorial of 1
Given I have the number 1
When I compute its factorial
Then I see the number 1
Scenario: Factorial of 2
Given I have the number 2
When I compute its factorial
Then I see the number 2
Scenario: Factorial of 3
Given I have the number 3
When I compute its factorial
Then I see the number 6
執行結果:
嗯??第四場景沒通過,3!=3*2*1=6 這個預期結果肯定是正確的,那就是程式碼的邏輯有問題吧!如果你細心的話一定發現了setup.py中的程式碼並未真正實現階乘,我們需要對它進行修改:
#coding=utf-8 from lettuce import * @step('I have the number (\d+)') def have_the_number(step, number): world.number = int(number) print world.number @step('I compute its factorial') def compute_its_fatorial(step): world.number = factorial(world.number) print world.number @step('I see the number (\d+)') def check_number(step, expected): expected = int(expected) assert world.number == expected, \ "Got %d" % world.number def factorial(number): number = int(number) if (number == 0) or (number == 1): return 1 else: return number*factorial(number-1)
程式碼修改部分:
def factorial(number): number = int(number) if (number == 0) or (number == 1): return 1 else: return number*factorial(number-1)
參照本文開頭,通過遞迴的方式實現階乘的程式碼,現在才算完整的實現階乘。OK !再來執行以下指令碼吧!全綠了有木有!!
這應該是目前講解BDD 最通俗易懂的文章了,沒有之一,給個贊吧!