スコープバインディング
SpecFlowのStepDefinition/Hookは、そのままだと、全ての試験に対して適用される。
それを、特定のフィーチャ/シナリオ/タグ でのみ実行されるように、限定する機能。
スコープバインディングが必要そうな例
例えば、以下のような2つのフィーチャがあったとする。
フィーチャ例1:
フィーチャ: ユーザ管理(サーバ)
@サーバ
シナリオ: 新規にユーザを追加する(サーバ)
前提 ユーザテーブルに新規追加するユーザと同じユーザの情報が存在しない
かつ 管理者としてログイン中
かつ 追加するユーザが一般ユーザ
もし 新規にユーザを追加する
ならば 一般ユーザが追加される
@サーバ
シナリオ: 新規にユーザを追加する(サーバ)
前提 ユーザテーブルに新規追加するユーザと同じユーザの情報が存在しない
かつ 管理者としてログイン中
かつ 追加するユーザが一般ユーザ
もし 新規にユーザを追加する
ならば 一般ユーザが追加される
フィーチャ例2
フィーチャ: ユーザ管理(クライアント)
@クライアント
シナリオ: 新規にユーザを追加する(クライアント)
前提 現在の表示情報に新規追加しようとしているユーザと同じユーザが存在しない
かつ 管理者としてログイン中
かつ 追加するユーザが一般ユーザ
もし 新規にユーザを追加する
ならば 一般ユーザが追加される
@クライアント
シナリオ: 新規にユーザを追加する(クライアント)
前提 現在の表示情報に新規追加しようとしているユーザと同じユーザが存在しない
かつ 管理者としてログイン中
かつ 追加するユーザが一般ユーザ
もし 新規にユーザを追加する
ならば 一般ユーザが追加される
上記の2つのフィーチャは、「前提」を除いて、ほぼ完全に記載内容が同一である。
クライアント側は表示内容から判断、操作を行い、
サーバ側は、テーブルの内容で判断、操作を行うという差分があるので、
実際に確認を行うStep Definitionファイルは、異なったものとならなければならない。
しかし、SpecFlowの実施時の制約として、全くおなじパターンの「前提」「もし」「ならば」は、テストコード上に2つは存在できない。
その為、上記のフィーチャファイルから、以下のようなファイルを作成すると、コンパイル時にはエラーが発生しないが、SpecFlowでの試験実施時に、エラーで落ちることになる。
フィーチャ1からのStep Definitionファイル例:
[Binding]
public class ユーザ管理クライアントSteps
{
[Given(@"現在の表示情報に新規追加しようとしているユーザと同じユーザが存在しない")]
public void 前提現在の表示情報に新規追加しようとしているユーザと同じユーザが存在しない()
{
// クライアント側に独自な処理
}
[Given(@"管理者としてログイン中")]
public void 前提管理者としてログイン中()
{
// クライアント側に独自な処理
}
[Given(@"追加するユーザが一般ユーザ")]
public void 前提追加するユーザが一般ユーザ()
{
// クライアント側に独自な処理
}
[When(@"新規にユーザを追加する")]
public void もし新規にユーザを追加する()
{
// クライアント側に独自な処理
}
[Then(@"一般ユーザが追加される")]
public void ならば一般ユーザが追加される()
{
// クライアント側に独自な処理
}
}
public class ユーザ管理クライアントSteps
{
[Given(@"現在の表示情報に新規追加しようとしているユーザと同じユーザが存在しない")]
public void 前提現在の表示情報に新規追加しようとしているユーザと同じユーザが存在しない()
{
// クライアント側に独自な処理
}
[Given(@"管理者としてログイン中")]
public void 前提管理者としてログイン中()
{
// クライアント側に独自な処理
}
[Given(@"追加するユーザが一般ユーザ")]
public void 前提追加するユーザが一般ユーザ()
{
// クライアント側に独自な処理
}
[When(@"新規にユーザを追加する")]
public void もし新規にユーザを追加する()
{
// クライアント側に独自な処理
}
[Then(@"一般ユーザが追加される")]
public void ならば一般ユーザが追加される()
{
// クライアント側に独自な処理
}
}
フィーチャ2からのStep Definitionファイル例:
[Binding]
public class ユーザ管理サーバSteps
{
[Given(@"ユーザテーブルに新規追加するユーザと同じユーザの情報が存在しない")]
public void 前提ユーザテーブルに新規追加するユーザと同じユーザの情報が存在しない()
{
// サーバ側に独自な処理
}
[Given(@"管理者としてログイン中")]
public void 前提管理者としてログイン中()
{
// サーバ側に独自な処理
}
[Given(@"追加するユーザが一般ユーザ")]
public void 前提追加するユーザが一般ユーザ()
{
// サーバ側に独自な処理
}
[When(@"新規にユーザを追加する")]
public void もし新規にユーザを追加する()
{
// サーバ側に独自な処理
}
[Then(@"一般ユーザが追加される")]
public void ならば一般ユーザが追加される()
{
// サーバ側に独自な処理
}
}
public class ユーザ管理サーバSteps
{
[Given(@"ユーザテーブルに新規追加するユーザと同じユーザの情報が存在しない")]
public void 前提ユーザテーブルに新規追加するユーザと同じユーザの情報が存在しない()
{
// サーバ側に独自な処理
}
[Given(@"管理者としてログイン中")]
public void 前提管理者としてログイン中()
{
// サーバ側に独自な処理
}
[Given(@"追加するユーザが一般ユーザ")]
public void 前提追加するユーザが一般ユーザ()
{
// サーバ側に独自な処理
}
[When(@"新規にユーザを追加する")]
public void もし新規にユーザを追加する()
{
// サーバ側に独自な処理
}
[Then(@"一般ユーザが追加される")]
public void ならば一般ユーザが追加される()
{
// サーバ側に独自な処理
}
}
上記のコードで試験を実行しても、実行時に以下のようなエラーとなる:
これは「追加するユーザが一般ユーザ」、「管理者としてログイン中」等のStepに対して、複数のメソッドが実行対象として検索される状態のため。
スコープバインディングの適用
スコープバインディングとは
Step Definition(上記コード例での、実際にテスト実施されるコード)を、特定のフィーチャだけに適用されるように、スコープをつけて、限定する機能。
スコープの属性一覧
- Feature - フィーチャ単位での限定
- Scenario - シナリオ単位での限定
- Tag - タグ単位の限定(タグの説明は、後述)
スコープの実装
スコープは、Step Definition, Hook に対する属性として実装される。
例えば、上記までの例について、「ユーザ管理サーバSteps」クラスを、フィーチャ「ユーザ管理(クライアント)」に限定するには、クラスに以下のように属性を追加する。
変更個所(2行目の”Scope”属性が追記箇所):
[Binding]
[Scope(Feature = "ユーザ管理(クライアント)")]
public class ユーザ管理クライアントSteps
[Scope(Feature = "ユーザ管理(クライアント)")]
public class ユーザ管理クライアントSteps
上記のように変更を加えたうえで、再度試験を実施すると、エラーが解消される。
実行結果例:
これは、片方の Step Definition が「フィーチャが”ユーザ管理(クライアント)”」側のみに限定されたため、サーバ側についても、各「前提」「もし」「ならば」に、複数のメソッドが該当することがなくなり、エラーが解消されたため。
※クライアント側、サーバ側のフィーチャで、それぞれ対応する側のStepが実行されていることも確認できる。
その他、実装上の注意
[Scope]属性は、クラスとメソッドどちらにも指定できる
指定例:
[Binding]
[Scope(Feature ="ユーザ管理")]
public class ユーザ管理クライアントSteps
{
[Given(@"管理者としてログイン中")]
[Scope(Scenario = "新規にユーザを追加する(クライアント)")]
public void 前提管理者としてログイン中()
{
// クライアント側に独自な処理
}
[Scope(Feature ="ユーザ管理")]
public class ユーザ管理クライアントSteps
{
[Given(@"管理者としてログイン中")]
[Scope(Scenario = "新規にユーザを追加する(クライアント)")]
public void 前提管理者としてログイン中()
{
// クライアント側に独自な処理
}
クラスに指定した場合には、そのクラス配下の全てのメソッドが、影響を受ける。
[Scope]属性は複数つけられる
複数指定した場合には、指定したいずれかのスコープに一致する場合に実行されるようになる。
複数個の指定例:
[Given(@"管理者としてログイン中")]
[Scope(Tag = "ウェブ")]
[Scope(Tag = "サーバ")]
public void 前提管理者としてログイン中()
[Scope(Tag = "ウェブ")]
[Scope(Tag = "サーバ")]
public void 前提管理者としてログイン中()
[Scope]属性は Feature, Scenario, Tag を組み合わせて設定できる
もし、複数設定した場合には、全ての条件を満たすStepのみが実行される。
複数記載の例:
[Scope(Feature ="ユーザ管理", Scenario ="管理者権限をはく奪する")]
上記のScopeの例だと、フィーチャ”ユーザ管理”の中で、”管理者権限をはく奪する”シナリオでのみに適用されるようになる。(どちらかだけ一致の場合には、適用されない)
タグとは
タグとは、フィーチャファイル上に定義する、フィーチャ、シナリオを構造化するための、フィーチャの記載方法の一つ。
タグの記載例
以下フィーチャの記載で、”@”が付いた薄緑色の部分が、タグである。
記載例:
@運用
フィーチャ: ユーザ管理
@サーバ
シナリオ: 新規にユーザを追加する(サーバ)
前提 ユーザテーブルに新規追加するユーザと同じユーザの情報が存在しない
かつ 管理者としてログイン中
かつ 追加するユーザが一般ユーザ
もし 新規にユーザを追加する
ならば 一般ユーザが追加される
@クライアント
シナリオ: 新規にユーザを追加する(クライアント)
前提 現在の表示情報に新規追加しようとしているユーザと同じユーザが存在しない
かつ 管理者としてログイン中
かつ 追加するユーザが一般ユーザ
もし 新規にユーザを追加する
ならば 一般ユーザが追加される
フィーチャ: ユーザ管理
@サーバ
シナリオ: 新規にユーザを追加する(サーバ)
前提 ユーザテーブルに新規追加するユーザと同じユーザの情報が存在しない
かつ 管理者としてログイン中
かつ 追加するユーザが一般ユーザ
もし 新規にユーザを追加する
ならば 一般ユーザが追加される
@クライアント
シナリオ: 新規にユーザを追加する(クライアント)
前提 現在の表示情報に新規追加しようとしているユーザと同じユーザが存在しない
かつ 管理者としてログイン中
かつ 追加するユーザが一般ユーザ
もし 新規にユーザを追加する
ならば 一般ユーザが追加される
タグは、「フィーチャ」、「シナリオ」 に対してつける事ができる。
また、スペースで区切って、複数個付ける事も出来る。
複数個例:
@クライアント @ウェブ @重要
シナリオ: 新規にユーザを追加する(クライアント)
シナリオ: 新規にユーザを追加する(クライアント)
上記の用に記載すると、シナリオが”クライアント”, “ウェブ”, “重要”のいずれかのスコープに一致するようになる。
以上。
0 件のコメント:
コメントを投稿