SpecFlowにて、共通的な処理を記載したり、細かい情報のロギング等に便利そうな機能、Hookの一通りの説明。
Hookとは
SpecFlowによる試験の実施時の特定のタイミング(フィーチャのテスト実施開始前後、シナリオの試験実施開始前後とか)に、自動的に実行されるメソッド。メソッドに、以下の属性を付与することで、実現する。
Hook属性一覧
属性タグ
|
いつ実施されるのか
|
[BeforeTestRun]
[AfterTestRun]
|
テスト全体の実施前後。
複数のフィーチャがある場合には、全てのフィーチャの実施より手前と、全てのフィーチャの試験が終わった後に実施される。
この属性タグをつけるメソッドは、静的メソッドである必要性がある。
※注意※
[AfterTestRun]は、テスト実施フレームワーク(MSTest, NUnitとか)のdllがアンロードされたタイミングで実施される。いつ実施されるのかは、各フレームワークによって異なる。
|
[BeforeFeature]
[AfterFeature]
|
各フィーチャのテスト実施前後。
フィーチャにシナリオが複数ある場合には、シナリオの試験実施が始まる前と、そのフィーチャのすべてのシナリオの実施が完了した後に実施される。
この属性タグをつけるメソッドは、静的メソッドである必要性がある。
|
[BeforeScenario] or [Before]
[AfterScenario] or [After]
|
フィーチャ内の各シナリオのテスト実施前後
各シナリオの実施前後に一度ずつ呼び出される。
|
[BeforeScenarioBlock]
[AfterScenarioBlock]
|
各シナリオ内の「前提」「もし」「ならば」のブロックの前後
(「前提」「もし」「ならば」に複数行の記載があったとしても、一度しか実施されない)
|
[BeforeStep]
[AfterStep]
|
各シナリオ内の「前提」「もし」「ならば」の各行の前後
(「前提」「もし」「ならば」に複数行の記載がある場合、その行数だけ実施される)
|
実装時の操作、挙動の説明
Hookクラスの簡単な挙動の説明と、クラス/メソッドの作成法等を説明する。
Hook クラスの新規作成
「StepFlow」の初期準備が終わったプロジェクトを右クリックし、「Add > Class...」を選択する。
テンプレートで「SpecFlow Hooks(event bindings)」を選択する。
任意の名前を入力し、「Add」ボタンをクリックする。
上記作業で、以下のような、SpecFlowのHook向けの空クラスが追加される。
[Binding]
public sealed class Hooks1
{
// For additional details on SpecFlow hooks see http://go.specflow.org/doc-hooks
[BeforeScenario]
public void BeforeScenario()
{
//TODO: implement logic that has to run before executing each scenario
}
[AfterScenario]
public void AfterScenario()
{
//TODO: implement logic that has to run after executing each scenario
}
}
(もし、手動でクラスを作る場合には、[Binding]属性の付与し忘れに注意。[Binding]
属性無しだと、SpecFlow実行時に、Hookとして認識されない)
とりあえず、全種類のHookの動作を試せるだけのコード例:
[Binding]
public sealed class SampleHooks
{
private int counter { get; set; }
[BeforeTestRun]
public static void doBeforeTestRun()
{
System.Console.WriteLine("Before Test Run:");
// 動作を確認したい場合には、以下の例外を出力するコードのコメントアウトを解除のこと
// throw new Exception("After Test Run");
}
[AfterTestRun]
public static void doAfterTestRun()
{
System.Console.WriteLine("After Test Run:");
// 動作を確認したい場合には、以下の例外を出力するコードのコメントアウトを解除のこと
// throw new Exception("After Test Run");
}
[BeforeFeature]
public static void doBeforeFeature()
{
System.Console.WriteLine("Before Feature:");
}
[AfterFeature]
public static void doAfterFeature()
{
System.Console.WriteLine("After Feature:");
}
[BeforeScenario]
public void doBeforeScenario()
{
System.Console.WriteLine("Before Scenario:" + ++this.counter);
}
[AfterScenario]
public void doAfterScenario()
{
System.Console.WriteLine("After Scenario:" + ++this.counter);
}
[BeforeScenarioBlock]
public void doBeforeSB()
{
System.Console.WriteLine("Before Scenario Block:" + ++this.counter);
}
[AfterScenarioBlock]
public void doAfterSB()
{
System.Console.WriteLine("After Scenario Block:" + ++this.counter);
}
[BeforeStep]
public void doBeforeStep()
{
System.Console.WriteLine("Before Step:" + ++this.counter);
}
[AfterStep]
public void doAfterStep()
{
System.Console.WriteLine("After Step:" + ++this.counter);
}
}
試験実行時のHookクラスのインスタンス生成について
Hookの属性([before]とか[after]とか)が付いたクラスのインスタンスは、各シナリオの試験実行時に、一回ずつ新規生成される。各シナリオで、Hookの属性がついているクラスは、毎度全てインスタンス化され、全てのHook関係の属性がついたメソッドが実行される。
試験実行時のHookの実行順序の指定
同じHook属性のメソッドが複数個定義されていた場合、順序を指定しない限りは、どちらが先に実行されるかは、定義されていない。
もし、順序を固定したい場合には、”Order”を指定する。
以下のように指定:
[BeforeScenario(Order = 100)]
public void BeforeScenarioSecond()
{
System.Console.WriteLine("Second");
}
[BeforeScenario(Order = 50)]
public void BeforeScenarioFirst()
{
System.Console.WriteLine("First");
}
同じHook属性内では、Order の数値が小さい順に実行される。上記の例では、「BeforeScenarioFirst」メソッドが、「BeforeScenarioSecond」メソッドよりも必ず手前に実行される。
その他、特記事項
Hook属性を付けたメソッドは、基本的にどのシナリオ/フィーチャからも呼び出されてしまうので、このままの状態だと、特定のフィーチャ、シナリオ向けの処理は記載しにくい。
「特定のフィーチャ、シナリオだけで実行されるHook」、「Hook属性を付けたメソッド内で、どのフィーチャ、どのシナリオで実行されているのか知る」等は、スコープバインディング、Context、という、別のSpecFlowの機能と組み合わせて実現する。
スコープバインディングは、ちょっと調べたみたので、こっちの投稿に簡単説明を記載。
Contextも、ちょっと調べてみたので、こっちの投稿に簡単説明を記載。
以上。