[Tool][Specflow]使用 Scope 標記 Step Binding

  • 4847
  • 0

[Tool][Specflow]使用 Scope 標記 Step Binding

前言

相信使用過 Specflow 來設計 feature 與 steps 的朋友,應該都有碰到一個尷尬的問題,就是 Steps 是全域的。因為 Scenario 上的 Step, 如 Given, When, Then 子句,如何與 Steps.cs 來對應,是透過對應的 attribute 來 binding ,如下圖所示:

image

這個 Scenario 上面的 When ,實際執行時是要執行哪一個方法,當我們從 When 呼叫計算運費 移至定義可以看到,其實 Step 與 Feature 是透過 [When(@"呼叫計算運費")] 來 binding ,如下圖所示:

image

然而當有多個 Feature 或 Scenario 擁有相同的 Step 描述時,Specflow 會很聰明地幫你指到同一個 Step 的方法上,讓開發人員可以重用 Scenario 的 Step 。這在同一個 Feature 檔中,即使是不同的 Scenario ,仍算是很 friendly 的功能,但是一旦跨 Feature ,很容易造成維護或追問題的困擾。例如,有三個貨運商要計算商品的運費,其 Feature 如下:

  1. 黑貓:
    image
  2. 郵局:
    image
  3. 新竹貨運:
    image

即使參數不同,但這些 Step 的描述都是相同的,因此預設都會使用同一個 function 。但問題來了,黑貓的計算運費,可能是要呼叫 BlackCat 的 CalculateFee() ,但郵局的計算運費,可能是要呼叫 PostOffice 的 CalculateFee() 。很明顯的,雖然描述都是計算運費,但實際上要測試的物件是不同的。

因此,雖然 Step 預設可以重用,但我們還是相當需要簡單的方式,讓我們可以建立專屬於某個 Feature 或 Scenario 的 Step 內容。

 

Scope Introduction

在 Specflow 中其實有提供一個 attribute: Scope 來滿足我們上述的需求。Scope attribute 如下圖所示:

image

可以發現這個 attribute 可以放在 Class 上,也可以放在 Method 上。放在 class 上代表,整個 Step 的 class 都是給這個 Scope 所定義的範圍使用。同樣地,放在 method 上就代表這個 step 方法內容,是專屬於某個 Feature, Scenario 或是 Tag 使用。

另外一個值得留意的是:AllowMultiple = true 。代表同樣的 attribute 可以重複標記在同一個 class 或 method 上。

來看一下例子,針對上面的 3 個 Feature 上,在 When 呼叫計算運費 上移至定義,都會移到「黑貓Steps 」上的方法。如下圖所示:

image

 

Scope with Feature

當我們一旦在 When 的方法上,加上 [Scope(Feature = "黑貓")] 代表這個 function 只給「Feature 黑貓」使用。

image

此時再回到郵局與新竹貨運的 Feature 上,可以發現這兩個 Feature 上 Scenario 的 「When 呼叫計算運費 」已經找不到對應的 binding 了。如下圖所示:

image

image

 

Scope with Multiple Feature

倘若這個呼叫計算運費的方法,也要給郵局這個 Feature 使用,只需要透過 multiple attribute 的標記方式即可,如下圖所示:

image

黑貓與郵局就都可以 binding 到上面這個 step ,如下所示:

image

 

Scope with Scenario

除了 Feature 等級, Scope 也可以納入特定的 Scenario 名稱,例如我們先將新竹貨運的 scenario 多增加幾個,如下所示:

image

可以看到When 呼叫計算運費都沒有 binding 到對應的 steps。

這時在 step 加上 [Scope(Scenario = "新竹貨運計算運費")] ,這樣就代表 Scenario 名稱為「新竹貨運計算運費」中的When 呼叫計算運費,就會跟這個方法 binding 起來。如下所示:

image

image

 

Scope with Tag

除了 Feature 與 Scenario 外,還有一個比較彈性的標記範圍方式: Tag 。如上圖所示,我們針對一個 Scenario 上,新增了一個 tag 名稱為 JoeyTag 。接著一樣在 Steps 方法上,加入 [Scope(Tag = "JoeyTag")] ,如下所示:

image

再檢視新竹貨運的 Scenarios ,可以看到有標記 @JoeyTag 的 Step 也可以被 binding 到了。如下所示:

image

 

個人建議

我個人的習慣,通常是考量團隊對測試的熟悉程度,我會讓 Feature 與 Steps 檔案做一對一的對應,也就是一個「黑貓 Feature」對應一個「黑貓 Steps」。所以我習慣在 Steps 的 class 上直接標記 [Scope(Feature="黑貓")] ,這樣同一個 Feature 中不同的 Scenario 仍可以共用 Steps ,又可以避免跨 Feature 的問題。如下所示:

image

如果有跨 Feature 共用的需求,尤其是 Event Binding 的需求,例如 BeforeScenario, BeforeFeature 之類的 event hook ,那建議直接新增一個 Hook 的 class 來處理,讓團隊在開發時有個 rule 可以 follow, 也讓維護的人更了解要去哪找到對應的程式碼。如下所示:

image

image

 

結論

因為 Specflow 的文件算是少的,希望之前跌跌撞撞摸索出來的一些小技巧,對想要了解的讀者有所幫助,可以更快樂地使用 BDD 與 Specflow 進行開發。

記得,善用 Scope ,定義出團隊規範,可以節省時間跟避免很多問題。


blog 與課程更新內容,請前往新站位置:http://tdd.best/