[SpecFlow]在測試程式中比較單一物件與物件集合
前言
前一篇文章:[Unit Testing]如何驗證兩個自訂型別物件集合相等 提到了如何比較自訂的物件,以及自訂物件的集合是否相等。(偷吃步可以透過 LINQ 的 SequenceEqual()
搭配匿名型別與 Tuple 來使用)
這篇文章,則是使用 SpecFlow 的 Assist Helper 直接從 Scenario 取得的測試案例資料進行比較。
範例
這篇文章簡單的舉了一個例子來說明,怎麼驗證自訂型別的單一物件以及集合。 Feature 檔如下:
Feature: 射手預備 Scenario: 第一位射手是誰 Given 射手群清單為 | Name | Id | | Joey | 1 | | Bill | 2 | | Demo | 3 | When I 取得第一位射手 #錯誤的測試案例,預期第一筆應該為Joey才對 Then 第一位射手應為 | Name | Id | | Bill | 2 | Scenario: 下一批射手預備 Given 射手群清單為 | Name | Id | | Joey | 1 | | Bill | 2 | | Demo | 3 | When I 呼叫下一波射手預備,一次 2 位 #錯誤的測試案例,預期第一筆應該為{Joey,1} 第二筆應為 {Bill,2}才對 Then 射手清單為 | Name | Id | | Joey | 2 | | Bill | 3 |
兩個測試案例可以看到刻意放了錯誤的 Then ,這裡是為了讓讀者們看到,當驗證失敗時,錯誤訊息的呈現方式。
接著來看重點, Steps 該怎麼設計。 Steps 程式碼如下:
using System.Collections.Generic;
using System.Linq;
using TechTalk.SpecFlow;
using TechTalk.SpecFlow.Assist;
namespace SpecflowAssertSample
{
[Binding]
[Scope(Feature = "射手預備")]
public class 射手預備Steps
{
private Target target;
[BeforeScenario]
public void BeforeScenario()
{
target = null;
}
[Given(@"射手群清單為")]
public void Given射手群清單為(Table table)
{
var shooters = table.CreateSet<Person>().ToList();
this.target = new Target(shooters);
}
[When(@"I 呼叫下一波射手預備,一次 (.*) 位")]
public void WhenI呼叫下一波射手預備一次N位(int count)
{
List<Person> actual = target.GetNext(count);
ScenarioContext.Current.Set<List<Person>>(actual);
}
[Then(@"射手清單為")]
public void Then射手清單為(Table table)
{
//var expected = table.CreateSet<Person>().ToList();
var actual = ScenarioContext.Current.Get<List<Person>>();
table.CompareToSet<Person>(actual);
}
[When(@"I 取得第一位射手")]
public void WhenI取得第一位射手()
{
Person actual = target.GetFirstShooter();
ScenarioContext.Current.Set<Person>(actual, "first");
}
[Then(@"第一位射手應為")]
public void Then第一位射手應為(Table table)
{
var actual = ScenarioContext.Current.Get<Person>("first");
//var expected = table.CreateInstance<Person>();
table.CompareToInstance<Person>(actual);
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Target
{
private List<Person> shooters;
public Target(List<Person> shooters)
{
this.shooters = shooters;
}
internal List<Person> GetNext(int count)
{
return this.shooters.Take(count).ToList();
}
internal Person GetFirstShooter()
{
return this.shooters.First();
}
}
}
重點說明:
- 要使用 SpecFlow 的 Assist Helper,記得引用 TechTalk.SpecFlow.Assist 的命名空間
-
table.CreateSet<T>
與table.CreateInstance<T>
的使用方式,請參考:[BDD][Tool][SpecFlow]Scenario 上使用 table 來呈現集合 -
重點在 Then 的部分,當要比較單一物件時,可以直接使用
table.CompareToInstance<T>(instance)
即可。 -
當要比較物件集合時,可以直接使用
table.CompareToSet<T>(set)
即可。
驗證失敗的訊息
第一個測試案例,因為是 Scenario 就寫錯了,所以 Expected 是 Scenario 上的。
第二個測試案例錯誤訊息如下:
可以看到驗證失敗訊息的呈現,要比自己用 MSTest 等 Assert 來得清楚許多, SpecFlow 會把 property 的名稱與值都顯示出來。
結論
有用 SpecFlow 的 table 來呈現物件時,除了需求與測試案例說明更加清楚以外,不管是單一物件或集合,在 Steps 中要進行取值或驗證,都是一塊小蛋糕。比起自己寫或其他 Test Framework 內建的 Assert ,要友善跟好用許多,相信這個小技巧,一定可以讓大家寫測試程式更加輕鬆簡便!
Reference
blog 與課程更新內容,請前往新站位置:http://tdd.best/