2016年7月31日日曜日

SpecFlow スコープバインディング(試験実行のフィルタリング)

スコープバインディング

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 ならば一般ユーザが追加される()
   {
       // クライアント側に独自な処理
   }
}

フィーチャ2からのStep Definitionファイル例:

[Binding]
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

上記のように変更を加えたうえで、再度試験を実施すると、エラーが解消される。

実行結果例:
これは、片方の Step Definition が「フィーチャが”ユーザ管理(クライアント)”」側のみに限定されたため、サーバ側についても、各「前提」「もし」「ならば」に、複数のメソッドが該当することがなくなり、エラーが解消されたため。
※クライアント側、サーバ側のフィーチャで、それぞれ対応する側のStepが実行されていることも確認できる。
   

その他、実装上の注意

[Scope]属性は、クラスとメソッドどちらにも指定できる

指定例:
[Binding]
[Scope(Feature ="ユーザ管理")]
public class ユーザ管理クライアントSteps
{
   [Given(@"管理者としてログイン中")]
   [Scope(Scenario = "新規にユーザを追加する(クライアント)")]
   public void 前提管理者としてログイン中()
   {
       // クライアント側に独自な処理
   }

    クラスに指定した場合には、そのクラス配下の全てのメソッドが、影響を受ける。

[Scope]属性は複数つけられる

複数指定した場合には、指定したいずれかのスコープに一致する場合に実行されるようになる。

複数個の指定例:
[Given(@"管理者としてログイン中")]
[Scope(Tag = "ウェブ")]
[Scope(Tag = "サーバ")]
public void 前提管理者としてログイン中()

[Scope]属性は Feature, Scenario, Tag を組み合わせて設定できる

もし、複数設定した場合には、全ての条件を満たすStepのみが実行される。
複数記載の例:
[Scope(Feature ="ユーザ管理", Scenario ="管理者権限をはく奪する")]
上記のScopeの例だと、フィーチャ”ユーザ管理”の中で、”管理者権限をはく奪する”シナリオでのみに適用されるようになる。(どちらかだけ一致の場合には、適用されない)

タグとは

タグとは、フィーチャファイル上に定義する、フィーチャ、シナリオを構造化するための、フィーチャの記載方法の一つ。

タグの記載例

以下フィーチャの記載で、”@”が付いた薄緑色の部分が、タグである。

記載例:
@運用
フィーチャ: ユーザ管理

@サーバ
シナリオ: 新規にユーザを追加する(サーバ)
    前提 ユーザテーブルに新規追加するユーザと同じユーザの情報が存在しない
    かつ 管理者としてログイン中
    かつ 追加するユーザが一般ユーザ
    もし 新規にユーザを追加する
    ならば 一般ユーザが追加される

@クライアント
シナリオ: 新規にユーザを追加する(クライアント)
    前提 現在の表示情報に新規追加しようとしているユーザと同じユーザが存在しない
    かつ 管理者としてログイン中
    かつ 追加するユーザが一般ユーザ
    もし 新規にユーザを追加する
    ならば 一般ユーザが追加される
タグは、「フィーチャ」、「シナリオ」 に対してつける事ができる。

また、スペースで区切って、複数個付ける事も出来る。
複数個例:
@クライアント @ウェブ @重要
シナリオ: 新規にユーザを追加する(クライアント)

上記の用に記載すると、シナリオが”クライアント”, “ウェブ”, “重要”のいずれかのスコープに一致するようになる。

以上。

0 件のコメント:

コメントを投稿