文章目錄
使用 SpecFlow 建立人語化的單元測試
如何寫出良好可讀性的程式是個持續性的挑戰,也可能是永無止盡的挑戰,而測試程式雖然目的是測試,但終究是程式,也需要具備良好的可讀性,加上測試程式擔負了需求描述及需求說明的功能,可讀性的要求比一般還要高,今天就來紀錄一下該如何使用 SpecFlow 建立人語化的單元測試,挑戰非開發人員也可以瞭解測試程式所代表的意思
什麼是 SpecFlow ?
官網 - SpecFlow 說明如下:
Use SpecFlow to define, manage and automatically execute human-readable acceptance tests in .NET projects. Writing easily understandable tests is a cornerstone of the BDD paradigm and also helps build up a living documentation of your system. SpecFlow is open source and provided under a BSD license. As part of the Cucumber family, SpecFlow uses the official Gherkin parser and supports the .NET framework, Xamarin and Mono. SpecFlow integrates with Visual Studio, but can be also used from the command line (e.g. on a build server). SpecFlow supports popular testing frameworks: MSTest, NUnit (2 and 3), xUnit 2 and MbUnit. SpecFlow+ adds additional functionality to SpecFlow, such as Visual Studio Test Explorer integration, a dedicated test runner with advanced test execution options, execution reports (HTML, XML, JSON) and much more.
個人理解重點是:
SpecFlow 可以用來開發非發人員也可以理解的驗證測試,這是 BDD 成功的基礎,還可以用來建立系統的即時文件
如何使用
參考官方文件 - SpecFlow+ Getting Started 加上個人安裝紀錄而來的,官網上範例是 VS 2013,我則會用 VS 2017
安裝 VS 套件
Visual Studio 主選單的 Tools –> Extensions and Updates
Online
tab –> 搜尋specflow
–> Download下載完成後請關閉 Visual Studio 2017 進行安裝
完裝完成後 Visual Studio 會加入 SpecFlow 的 template
專案加入 SpecFlow
專案上按右鍵 –> Manage NuGet Packages…
Browse –> 搜尋
specflow
–> 依 test framework 來安裝 (MSTest 只需安裝 SpecFlow 即可)有相依套件,直接安裝即可
調整使用的 Test Framework
SpecFlow 支援主流 Test Framework:MSTest, NUnit (2 and 3), xUnit 2 and MbUnit.預設使用 NUnit,如果要用其他 Test Framework ,就需要調整測試專案的 app.config 設定,以下的 demo 會以 NUint 為例
MSTest
<specFlow> <unitTestProvider name="MsTest" /> </specFlow>
xUnit.net 2.0
<specFlow> <unitTestProvider name="xUnit" /> </specFlow>
其他 test framework 設定值可以參考 Unit test providers
app.config 完整設定範例,官方文件請參考 Configuration
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow"/> </configSections> <specFlow> <unitTestProvider name="MsTest" /> </specFlow> </configuration>
加入 Feature 檔
在完成 SpecFlow 安裝後,Visual Studio 就擁有各式 SpecFlow 的 template,我們可以透過這些 template 來產生 feature 檔
在專案按下右鍵 –> Add –> New Item…
選擇 SpecFlow Feature File template–> 調整 feature 檔名 –> Add
依需求修改 Feature 檔
Feature: Calculator In order to 減少莫名其妙的錯誤 As 一個數學白痴 我想要得到兩數相加的結果 @myCalculator Scenario: 兩數相加 Given 第一個數字輸入 50 And 第二個數字輸入 70 When 按下 add Then 結果應該為 120
Feature
是情境描述,就是 user story@myCalculator
是用來為 scenario 加上識別標記Scenario
是實際用來執行的 test case,會以 regular expression 來 parse 參數
產生 Step Definitions
這就是測試程式的主體,
Given
是單元測試 3A 中的Arrange
When
是單元測試 3A 中的Act
Then
是單元測試 3A 中的Assert
產生前 Scenario 中的參數說明都會是
紫
色的在
Scenario
按右鍵 –> Generate Step Definitions如果這邊沒有
Generate Step Definitions
選項,記得專案要安裝 SpecFlow按下
Generate
產生檔案複製產生結果
如果已產生過檔案,再產生一次檔案會直接覆蓋,複製的功能在此時就很好用了
將結果產生至檔案
預設路徑不是當前路徑,要注意別放錯位置
產生 Step Definitions 後 Scenario 中的參數說明都會變成
白
色的,參數部部則是灰
色
實作測試程式 (Step Definitions)
加上測試目標
private Calculator target;
使用 IDE 產生 Calculator class (意圖導向開發)
建立初始化 target 並加上
[BeforeScenario]
[BeforeScenario] private void Init() { target = new Calculator(); }
修改
Given第一個數字輸入
方法參數名稱使其有意義public void Given第一個數字輸入(int first)
修改
Given第一個數字輸入
方法實作因為要讓值跨不同 method 使用,所以需要註冊 key 的及內容存進 ScenarioContext
ScenarioContext.Current.Set<int>(first, "first");
比照上述二步驟調整
Given第二個數字輸入
方法[Given(@"第二個數字輸入 (.*)")] public void Given第二個數字輸入(int second) { ScenarioContext.Current.Set<int>(second, "second"); }
修改
When按下Add
方法實作內容[When(@"按下 add")] public void When按下Add() { //取得 first var first = ScenarioContext.Current.Get<int>("first"); //取得 second var second = ScenarioContext.Current.Get<int>("second"); // 呼叫 target 的 add 方法,這個 Add 可以用 ide 自動產生至 Calculator class 中 int actual = target.Add(first, second); //將結果存入 ScenarioContext,不給 key 也可以當做 key ScenarioContext.Current.Set<int>(actual); }
實作 Calculator 的 Add 方法
internal int Add(int first, int second) { return first + second; }
修改
Then結果應該為
方法參數名稱及實作[Then(@"結果應該為 (.*)")] public void Then結果應該為(int expected) { //取得上一步 result 計算的結果 var actual = ScenarioContext.Current.Get<int>(); //驗證計算結果是否合乎預期 Assert.AreEqual(expected, actual); }
可以執行或是 debug 也可以下中斷點
可以自由在 feature 的 scenario 與 step definition 切換
從 feature 的 scenario 跳至 step definition
從 step definition 跳至 scenario
如果 step 被多個 scenario 使用會出現選擇視窗
心得
透過 SpecFlow 就可以讓測試程式擁有說人話的能力,也更能充份說明需求,讓程式與需求的隔閡縮小,加上同樣模式的驗證都可以利用加入 scenario 後直接套用原本的測試程式就好,不必多寫測試程式,讓撰寫測試程式的 effort 縮小很多,是不是很棒呀?!
參考資訊
文章作者 Yowko Tsai
上次更新 2021-10-26
授權合約
本部落格 (Yowko's Notes) 所有的文章內容(包含圖片),任何轉載行為,必須通知並獲本部落格作者 (Yowko Tsai) 的同意始得轉載,且轉載皆須註明出處與作者。
Yowko's Notes 由 Yowko Tsai 製作,以創用CC 姓名標示-非商業性-相同方式分享 3.0 台灣 授權條款 釋出。