SpecFlow上で実行できる、フィーチャの記載サンプルをいくつか以下に示す。
生成されるStep Definition についても、コード例を同時に示す。
主に、以下を参考に記載:
最低限のSpecFlow準備
もし、記載したフィーチャを実際に動作させて試したい場合には、単体テストプロジェクトを新規追加して、この投稿の「SpecFlow初期化」部分だけを実行すれば簡単です。
上記に加えて、App.config の設定を、以下のとおりに変更すると日本語でのフィーチャの記載がさらに楽になります。
<specFlow>
<language feature="ja-JP" />
<unitTestProvider name="MsTest" />
</specFlow>
上記赤字部分の設定で、フィーチャファイルがデフォルトで日本語状態になります。
記載サンプル
普通のシナリオ
ごくごく普通のシナリオの記載。
機能: 計算機機能
計算機。電卓風計算機能の動作仕様。
シナリオ: 二つの値を足し算する
前提 計算機に 50 と 100 を入力した
もし プラスボタンを押した
ならば 結果として 150 が表示される
各部分の説明
「機能:」に記載された部分から、「シナリオ:」まで直前の行までの記載は、テスト実行時には無視される。
「シナリオ:」部分に、確認したいシナリオのタイトルを記載する。これは、一つのフィーチャの中では、重複してはならない(同じシナリオは、一つのフィーチャに二つは定義できない)
「前提」、「もし」、「ならば」に該当する部分の記載が、テスト実行時のインプットとなる。
コード例:
[Given(@"計算機に (.*) と (.*) を入力した")]
public void 前提計算機にとを入力した(int p0, int p1)
{
// 実装は省略
}
[When(@"プラスボタンを押した")]
public void もしプラスボタンを押した()
{
// 実装は省略
}
[Then(@"結果として (.*) が表示される")]
public void ならば結果としてが表示される(int p0)
{
// 実装は省略
}
上記のコード例でシナリオのテストを実行した場合、メソッド「前提計算機にとを入力した(int p0, int p1)」の引数p0には”50”が、p1には、”150”が、それぞれ引き渡される。
テーブル
複数の値を、一度に「前提」「もし」「ならば」への入力して用いたい場合の記載例。
記載例:
機能: 会計年度ごと集計
会計年度ごとに集計処理を行う。
シナリオ: 年度ごと集計
前提 各年月の金額が以下の通りの内容である場合
| 年月 | 金額 |
| 201312 | 1100 |
| 201401 | 1200 |
| 201403 | 1300 |
| 201404 | 1401 |
| 201405 | 1502 |
もし 会計年度ごと集計機能を起動した
ならば 各年度の集計金額は以下の通りとなる
| 年度 | 合計金額 |
| 2013 | 3600 |
| 2014 | 2903 |
上記の「前提」、「ならば」の下に記載した”|”で挟まれた領域が、テーブルとして、Bindingのコードへ引き渡される。
コード例:
[Given(@"各年月の金額が以下の通りの内容である場合")]
public void 前提各年月の金額が以下の通りの内容である場合(Table table)
{
// 実装は省略
}
[When(@"会計年度ごと集計機能を起動した")]
public void もし会計年度ごと集計機能を起動した()
{
// 実装は省略
}
[Then(@"各年度の集計金額は以下の通りとなる")]
public void ならば各年度の集計金額は以下の通りとなる(Table table)
{
// 実装は省略
}
上記コード例での引数「Table table」の中身は、以下のように取り出す。
string val = table.Rows[0][0]; // 1行目の1列目の値をとりだす
string val = table.Rows[0]["合計金額"]; // 1行目の「合計金額」列の値をとりだす
// テーブルの各行の値を取り出す
foreach (TableRow row in table.Rows)
{
string year = row["年度"]; // 「年度」列の値をとりだす
string amount = row["合計金額"]; // 「合計金額」列の値をとりだす
}
なお、中身は、記載内容にかかわらず、文字列として扱われる。
(ただの数値が記載してあっても、文字列)
ドキュメント文字列(Doc Strings)
あるステップに対して、複数行の文字列データを引数として引き渡す記載方法。
記載例:
機能: 質問投稿機能
質問を投稿する機能。
シナリオ: 質問を投稿
前提 質問者名に名前を入力していない
かつ 以下質問を入力している
"""
購入した商品の産地について、
届けられた商品に記載された産地が、
サイト上の商品説明と一致してないように見える。
この商品の産地について、正しい情報を教えて欲しい。
"""
もし 質問を投稿した
ならば 結果として新規の投稿受付番号が表示される
かつ オペレータに投稿受付番号が通知される
質問を投稿する機能。
シナリオ: 質問を投稿
前提 質問者名に名前を入力していない
かつ 以下質問を入力している
"""
購入した商品の産地について、
届けられた商品に記載された産地が、
サイト上の商品説明と一致してないように見える。
この商品の産地について、正しい情報を教えて欲しい。
"""
もし 質問を投稿した
ならば 結果として新規の投稿受付番号が表示される
かつ オペレータに投稿受付番号が通知される
二つ目の前提「かつ」部分の下で「”””」で囲まれた部分が、試験実行時に最後の引数として引き渡される。
コード例:
[Binding]
public class 質問投稿機能Steps
{
[Given(@"質問者名に名前を入力していない")]
public void 前提質問者名に名前を入力していない()
{
// 実装内容は省略
}
[Given(@"以下質問を入力している")]
public void 前提以下質問を入力している(string multilineText)
{
// 実装内容は省略
}
[When(@"質問を投稿した")]
public void もし質問を投稿した()
{
// 実装内容は省略
}
[Then(@"結果として新規の投稿受付番号が表示される")]
public void ならば結果として新規の投稿受付番号が表示される()
{
// 実装内容は省略
}
[Then(@"オペレータに投稿受付番号が通知される")]
public void ならばオペレータに投稿受付番号が通知される()
{
// 実装内容は省略
}
}
public class 質問投稿機能Steps
{
[Given(@"質問者名に名前を入力していない")]
public void 前提質問者名に名前を入力していない()
{
// 実装内容は省略
}
[Given(@"以下質問を入力している")]
public void 前提以下質問を入力している(string multilineText)
{
// 実装内容は省略
}
[When(@"質問を投稿した")]
public void もし質問を投稿した()
{
// 実装内容は省略
}
[Then(@"結果として新規の投稿受付番号が表示される")]
public void ならば結果として新規の投稿受付番号が表示される()
{
// 実装内容は省略
}
[Then(@"オペレータに投稿受付番号が通知される")]
public void ならばオペレータに投稿受付番号が通知される()
{
// 実装内容は省略
}
}
なお、この状態で実行した場合には、”multilineText”引数には、以下のような内容が引き渡される。
シナリオアウトライン
同じ内容のシナリオに対して、複数パターンの値を記載する必要がある場合の記載方法。
記載例:
シナリオアウトライン: 二つの値を引き算する
前提 計算機に <最初の入力> と <次の入力> を入力した
もし マイナスボタンを押した
ならば 結果として <計算結果> が表示される
例:
| 最初の入力 | 次の入力 | 計算結果 |
| 10 | 5 | 5 |
| 50 | 1 | 49 |
| 5 | 10 | -5 |
上記の「シナリオアウトライン」部分に記載された内容の中で、”<>”で囲まれた部分が、後続の「例:」に記載されたテーブル上の対応列の内容で置き換えられ、別々のシナリオとして解釈される。
上記の記載例ならば、例えば「例」の1行目については、以下の普通シナリオと同様に扱われる。
シナリオ: 二つの値を引き算する
前提 計算機に 10 と 5 を入力した
もし マイナスボタンを押した
ならば 結果として 5 が表示される
※「例:」に3行分のデータがあるので、SpecFlowでのテスト実行時には、3つ分のシナリオとして扱われる。
コード例:
シナリオアウトラインをテストするコードについても、普通のシナリオのそれと変化はない。
[Given(@"計算機に (.*) と (.*) を入力した")]
public void 前提計算機にとを入力した(int p0, int p1)
{
// 実装は省略
}
[When(@"マイナスボタンを押した")]
public void もしマイナスボタンを押した()
{
// 実装は省略
}
[Then(@"結果として (.*) が表示される")]
public void ならば結果としてが表示される(int p0)
{
// 実装は省略
}
SpecFlowでの実行時には、以下のように、3つのシナリオとして別々に実行される。
背景
複数のシナリオにおいて、共通の前提条件(満たすべきデータとか、ユーザの種類とか)が存在する場合に便利な記載方法。
記載例:
機能: ユーザ管理
ユーザの追加機能。管理者のみが利用できる。
全シナリオ共通の「背景」のサンプル。
背景:
前提 管理者としてログインしている
かつ システムに以下のユーザが存在する
| ユーザID | ユーザ名 |
| TARO1 | 一般 太郎 |
| JIRO2 | 一般 次郎 |
| ADM3 | 管理者 三郎 |
シナリオ: ユーザを追加する
もし 以下のユーザを追加した
| ユーザID | ユーザ名 |
| SIRO1 | 一般 四朗 |
ならば システムに存在するユーザは以下の通りとなる
| ユーザID | ユーザ名 |
| TARO1 | 一般 太郎 |
| JIRO2 | 一般 次郎 |
| ADM3 | 管理者 三郎 |
| SIRO1 | 一般 四朗 |
シナリオ: ユーザを削除する
もし ユーザ 一般次郎 を削除した
ならば システムに存在するユーザは以下の通りとなる
| ユーザID | ユーザ名 |
| TARO1 | 一般 太郎 |
| ADM3 | 管理者 三郎 |
上記記載例で「背景:」として記載された内容が、続いて記載されている二つのシナリオ双方に適用される。上記の試験実行時には、二つのシナリオそれぞれで、「背景」に記載された内容が実行される。
コード例:
コードは、普通のシナリオと差はない。
[Given(@"管理者としてログインしている")]
public void 前提管理者としてログインしている()
{
// 実装は省略
}
[Given(@"システムに以下のユーザが存在する")]
public void 前提システムに以下のユーザが存在する(Table table)
{
// 実装は省略
}
[When(@"以下のユーザを追加した")]
public void もし以下のユーザを追加した(Table table)
{
// 実装は省略
}
[When(@"ユーザ 一般次郎 を削除した")]
public void もしユーザ一般次郎を削除した()
{
// 実装は省略
}
[Then(@"システムに存在するユーザは以下の通りとなる")]
public void ならばシステムに存在するユーザは以下の通りとなる(Table table)
{
// 実装は省略
}
試験実行結果例:
各シナリオには「もし」と「ならば」しか記載されていないが、SpecFlowでの試験実行時には、各シナリオの「もし」部分の実行前に、「背景」に記載された「前提」が2つ、実行されるのが確認できる。
かつ、しかし
「前提」「もし」「ならば」の部分に、複数の条件、動作を記載したい場合には、以下のようにかける。
記載例:
機能:都知事選
シナリオ: 都知事になる
前提 日本国民
かつ 被選挙権がある
かつ 人気がある
かつ 実力がある
しかし 犯罪をおかしていない
もし 都知事選に立候補する
かつ 法律を守る
ならば 都知事になれる
しかし 苦労する
これは、以下のように記載するのと同じである。
機能:都知事選
シナリオ: 都知事になる
前提 日本国民
前提 被選挙権がある
前提 人気がある
前提 実力がある
前提 犯罪をおかしていない
もし 都知事選に立候補する
もし 法律を守る
ならば 都知事になれる
ならば 苦労する
コード上でも、二つの記載方法で差は出ない。
補足:同義語の一覧
いくつかの用語について、どちらで記載しても問題ない同義語が存在する。
一覧は、以下の通り:
英語
|
日本語
|
同義語
|
and
|
かつ
| |
background
|
背景
| |
but
|
しかし
|
但し, ただし
|
examples
|
例
|
サンプル
|
feature
|
フィーチャ
|
機能
|
given
|
前提
| |
scenario
|
シナリオ
| |
scenarioOutline
|
シナリオアウトライン
|
シナリオテンプレート, テンプレ, シナリオテンプレ
|
then
|
ならば
| |
when
|
もし
|
SpecFlow が動作する環境が整っているのであれば、入れ替えてみて、実際に動作に差分が無いのを確認してみていただきたい。
大体のフィーチャの記載方法については、以上で問題ないはず。
SpecFlowは、Cucumberの「Gherkin」のルールに従っているので、Cucumberでも上記の記載ルールはそのまま使用できると思われる。
以上。
0 件のコメント:
コメントを投稿