D-04-開始測試 ? mstest ? specflow

撰寫測試

相信很多人會想要增加系統的穩定度,但是這該如何做則是個問題,相信很多人看過91 TDD的文章,也相信希望能從單元測試增加系統的穩定度以及正確性,不過在dotnetcore內要如何寫測試案例呢,今天就讓我們來研究一下vscode怎麼用specflow來寫測試案例。

測試案例

「前輩,為什麼我們常常會寫出很多bug」
今天小光跟大頭請教怎麼增加程式穩定度及正確性的問題,不過聽到這問題後大頭也只是歪著頭思考著,也沒有正面回應小光的疑問。
「其實這也是苦惱我好久的問題」
「還是我們兩個一起去問老K前輩呢」
「這好像是不錯的解決方式。」
所以他們兩個就一起來尋問老K該如何處理這問題,不過當他們問老K之後確得到這樣的答案。
「這問題可能只能問上帝了,因為人非聖賢孰能無過。」
聽了這個答案後兩個人都倒抽了一口氣,而且整個像是洩氣的皮球,不過大頭立刻意會到他們問錯問題了,所以大頭又換個方式問了一次。
「前輩,我們該如何減少bug的產生呢。」
聽了大頭問的問題後老K哈哈大笑,並且這麼說。
「孺子可教也,我們沒辦法不寫出bug,但是我們能想辦法減少寫出bug的狀況,以及檢查有沒有寫出bug。」
說完了這句話後老K喝了杯水,並且起身走了幾步後示意大頭跟小光跟上來。所以小光跟大頭就跟著老K往辦公室外面走去。走到外面公園後老K開始說起來了。
「系統、需求跟程式都是人設計的,所以依據理解力及細心程度不同所做出來的東西完成度也會不同。」
這時老K走到樹下的座椅上坐了下來,並且繼續說。
「不過還是可以透過人與人之間的配合來檢驗出系統有沒有問題,所以這時除了整合測試之外也可以透過單元測試及早知道元件的正確性。」
說到這裡大頭似乎有點疑問,所以問了一個問題。
「但是要怎麼讓QA或是企劃來配合檢驗系統呢,一定要等到系統完成後再來檢驗嗎?」
這時老K點點頭,因為大頭問了一個好問題。
「這時可以RD跟QA還有企劃一起進行BDD」

BDD

所以重點來了,什麼是BDD呢,BDD是Behavior-driven development的簡稱,他鼓勵RD跟QA還有非技術人員協作開發,不過這怎麼做到,非技術人員對於程式碼的撰寫應該不清楚。所以這時候就是讓非技術人員透過自然語言寫出測試案例,並且說明其重點所在,如此程式開發人員可以更著重於系統的開發以符合測試案例的檢驗。這樣可以大大的減少程式人員與非技術人員之間的溝通成本,除此之外也可以有一份程式的說明文件可以提供給相關人員了解內容。

BDD 如何撰寫

所以要怎麼撰寫才可以讓人了解程式的作用以及其價值呢,因此要遵循一個大家公認的規則來寫這份文件,所以就BDD的範例來說這份文件要包含下列內容。

段落 內容說明 包含資訊
Title 說明此程式的商業價值 簡述這段程式做什麼的
Narrative 簡短的介紹這章節 As a 某種身份 I want 做某件事情 so that 會得到什麼結果
Acceptance criteria 說明情境以及如何應對 Scenario Given And When Then

specflow

說了那麼多BDD得概念,不過如何把程式開發跟BDD和在一起呢,這時我們就需要一個Specflow的工具,這工具就是幫我們剛剛說的BDD所寫下來的自然語言產生程式結構,透過實作Step來達成測試我們程式正確性的工具。在Visual Studio跟Rider有較好的支援,不過我們目前使用的是VSCode,所以今天就來認識如何用VSCode來撰寫測試案例以及驗證程式的正確性。

環境設定

這裡我們需要產生一個新的專案,但是在產生專案之前要先安裝些東西,所以先要完成的是環境設定,這邊先參考安裝Specflow的內容來安裝VSCode的擴充元件Awesome DotNetCore PackCucumber (Gherkin) Full Support。在安裝完成後再設定檔指定Specflow中放置Step的程式碼的資料夾以及檔案名稱的模式,路徑為檔案->喜好設定->設定後在搜尋欄篩選Cucumber之後找到Cucumberautocomplete.Steps按下編輯後輸入以下內容。

"cucumberautocomplete.steps": ["/**/Steps/**/*.cs"]

這樣設定完之後我們可以在feature檔案上透過ctrl+click立刻連結到Step的程式碼上,如此VSCode的設定告一段落。不過要重頭寫feature是一件麻煩的事,而且建立空專案也是一樣,所以接下來要針對dotnet cli加以設定,這邊參考新增Specflow範本的步驟來新增specflow的範本。所以首先先在命令列輸入以下內容。

dotnet new -i SpecFlow.Templates.DotNet

透過上述指令可以新增Specflow的範本到donet cli內,當新增完之後我們就可以使用範本來產生專案以及feature範本,所以我們先產生一個空的專案。

dotnet new specflowproject --unittestprovider mstest --framework net5.0 -o Tests

如此我們就可以產生一個空的specflow的專案,接下來我們可以產生一個空的函式庫只要輸入一下內容。

dotnet new classlib --framework net5.0 -o Libs

接下來再將相依的套件都先加入進來,輸入以下指令。

dotnet add package MSTest.TestFramework -v 2.2.7
dotnet add package MSTest.TestAdapter -v2.2.7

當空專案產生好了之後,這時只要在測試專案中參考函式庫就可以針對函式庫的內容撰寫測試案例了,這裡參考的指令如下。

dotnet add reference ../Libs/Libs.csproj

所以先在函式庫中寫一個要測試的方法,如下所示。

public class Calculator
{
    public int Add(int first, int second)
    {
        return 0;
    }
}

所以接下來我們要開始寫測試案例了。

測試案例撰寫

如果透過前面的步驟產生specflow專案的話我們應該可以看到內部已經有些些範例檔案了,例如Calculator.feature,我們就以這檔案來開始說明。

Feature: Calculator # 表頭,以下說明該程式的功用,Feature: 後面接的可以用來設定特定Step才能綁定該feature
![Calculator](https://specflow.org/wp-content/uploads/2020/09/calculator.png)
Simple calculator for adding **two** numbers

Link to a feature: [Calculator]($projectname$/Features/Calculator.feature)
***Further read***: **[Learn more about how to generate Living Documentation](https://docs.specflow.org/projects/specflow-livingdoc/en/latest/LivingDocGenerator/Generating-Documentation.html)**

@mytag # tag
Scenario: Add two numbers # 情境的名稱,不能重複
    Given the first number is 50 # Give 給予參數
    And the second number is 70 # And 接續上一個的指令,在這是Given
    When the two numbers are added # When 執行動作
    Then the result should be 120 # Then 檢查結果

Step實作

由於透過Cucumber (Gherkin) Full Support插件我們可以看到那些feature的語句沒有綁訂到Step上面,所以這邊可以看一下範例中的CalculatorStepDefinitions.cs

[Given("the first number is (.*)")]
public void GivenTheFirstNumberIs(int number)
{
    //TODO: implement arrange (precondition) logic
    _scenarioContext.Add("First", number);
}

[Given("the second number is (.*)")]
public void GivenTheSecondNumberIs(int number)
{
    //TODO: implement arrange (precondition) logic
     _scenarioContext.Add("Second", number);
 }

[When("the two numbers are added")]
public void WhenTheTwoNumbersAreAdded()
{
    //TODO: implement act (action) logic
     var first = _scenarioContext.Get<int>("First");
     var second = _scenarioContext.Get<int>("Second");
     var target = new Libs.Calculator();
    _scenarioContext.Add("Result", target.Add(first, second));
}

[Then("the result should be (.*)")]
public void ThenTheResultShouldBe(int result)
{
    //TODO: implement assert (verification) logic
     var expect = _scenarioContext.Get<int>("Result");
     Assert.AreEqual(result, expect);
}

不過就算這補完後執行測試也是收到錯誤,因為我們原來的方法本來就是錯的,所以接下來再把函式庫的方法修正如下。

    public int Add(int first, int second)
    {
        return first + second;
    }

如此執行完後應該會有測試成功的訊息,最後在說明一下如果需要綁定某個feature的話,只要在class上面設定這個attribute即可。

[Scope(Feature = "Calculator")]
    [Binding]
    public class CalculatorStepDefinitions

後記

今天跟大頭還有小光了解了要怎麼透過測試案例來增加程式的正確性,並且學習到如何透過vscode來撰寫specflow的features。希望對大家減少bug有所幫助。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *