TDD 練習 (1) – 從 Unit Test 到 Specflow

      在〈TDD 練習 (1) – 從 Unit Test 到 Specflow〉中留言功能已關閉

使用 LeetCode 771 練習測試

題目大致上就是有個變數 J 跟 S,輸出在S 與 J 匹配的字元數量。(且 J 不會重覆字元)

所以

  • J = “aA” , S = “aAAbbbb” 輸出為 3
  • J = “z” , S = “ZZ” 輸出為 0

 

 

建立一個 Unit Test 專案 命名為 : LeetCode771JewelsAndStonesTests

 

Unit Test 的 3A 原則

  • Arrange – 初始化
  • Act – 執行
  • Actual – 驗證結果

建立第一個測試 :

        [TestMethod]
        public void NumJewelsInStonesTest_When_J_Is_aA_And_S_Is_aAAbbbb_Should_Be_3()
        {
            //Arrange
            var solution = new Solution();
            var J = "aA";
            var S = "aAAbbbb";

            //Act
            var actual = solution.NumJewelsInStones(J, S);

            //Assert
            var expected = 3;
            Assert.AreEqual(expected, actual);
        }

產生空的 Solution.cs :

    public class Solution
    {
        public int NumJewelsInStones(string J, string S)
        {
            throw new System.NotImplementedException();
        }
    }

 

撰寫程式碼,通過測試 :

    public class Solution
    {
        public int NumJewelsInStones(string J, string S)
        {
            int count = 0;
            var js = J.ToArray();

            var ss = S.ToArray();

            foreach (var j in js)
            {
                foreach (var s in ss)
                {
                    if (j == s)
                    {
                        count++;
                    }
                }
            }

            return count;
        }
    }

建立第二個測試 :

        [TestMethod]
        public void NumJewelsInStonesTest_When_J_Is_z_And_S_Is_ZZ_Should_Be_0()
        {
            //Arrange
            var solution = new Solution();
            var J = "z";
            var S = "ZZ";

            //Act
            var actual = solution.NumJewelsInStones(J, S);

            //Assert
            var expected = 0;
            Assert.AreEqual(expected, actual);
        }

由於可以直接通過測試 可以執行 Ctrl + RT (當前測試) 或 Ctrl + RA (所有測試)

安裝 Specflow

需先安裝 Visual Studio Extension (需重新啟動 Visual Studio)

 Nuget 安裝 Specflow

建立 SpecflowFeature

專案,按右鍵,新增檔案

 

修改 Scenario :

Feature: Jewels and Stones

@mytag
Scenario: NumJewelsInStones
	Given I have entered J aA into the solution
	And I have entered S aAAbbbb into the solution
	When I press NumJewelsInStones
	Then the result should be 3 on the screen

 

右鍵產生 Steps

會新增一個 JewelsAndStonesSteps.cs

但你會發現變數並沒有帶入,所以要手動把它修改成  (.*) 跟傳入參數

回到 feature 會看到變數已有運作 :

直接建置的話會出現找不到 NUnit

因預設使用 NUnit 但這邊使用 MSTest 所以修正 App.config 使用 MsTest

 <unitTestProvider name="MsTest" />

測試會顯示出來,此時已可以建置或執行測試 :

Specflow 的 JewelsAndStonesSteps.cs 程式部分 :

步驟跟 Unit Test 一樣,只是需要先用 ScenarioContext.Current.Add(key,value) 把值存起來

 ScenarioContext.Current.Get<type>(key) 取值 :

    public class JewelsAndStonesSteps
    {
        [Given(@"I have entered J (.*) into the solution")]
        public void GivenIHaveEnteredJIntoTheSolution(string J)
        {
            ScenarioContext.Current.Add("J",J);
        }
        
        [Given(@"I have entered S (.*) into the solution")]
        public void GivenIHaveEnteredSIntoTheSolution(string S)
        {
            ScenarioContext.Current.Add("S", S);
        }
        
        [When(@"I press NumJewelsInStones")]
        public void WhenIPressNumJewelsInStones()
        {
            var solution = new Solution();
            var J = ScenarioContext.Current.Get<string>("J");
            var S = ScenarioContext.Current.Get<string>("S");
            var actual = solution.NumJewelsInStones(J, S);
            ScenarioContext.Current.Add("actual", actual);
        }
        
        [Then(@"the result should be (.*) on the screen")]
        public void ThenTheResultShouldBeOnTheScreen(int expected)
        {
            var actual = ScenarioContext.Current.Get<int>("actual");

            Assert.AreEqual(expected, actual);
        }
    }

 

完成測試後,需要建立第二個測試,由於步驟都跟第一個步驟完全相同,所以可以將 Scenario 轉成 Scenario Outline ,並建立 Examples

 

Scenario Outline: NumJewelsInStones
	Given I have entered J <J> into the solution
	And I have entered S <S> into the solution
	When I press NumJewelsInStones
	Then the result should be <result> on the screen

	Examples: 
	| J  | S       | result |
	| aA | aAAbbbb | 3      |
	| z  | ZZ      | 0      |

 

最後,執行測試 :

print