BDD 'Given'ステップの説明と実装

あなたは通常どのようにシナリオのために「与えられた」ステップを記述し実装しますか?

  1. 上位レベルの状態記述または明示的なデータ定義ですか?
  2. データベースまたはスタブリポジトリを入力しますか?

上位レベルの状態の説明

Given I have 4 プロducts
When I look for best-selling プロducts
Then I see top 3 プロducts with maximum number of sales

プロ

  • 脆弱ではない
  • ビジネス目標を読みやすく、理解しやすい

CON

  • 必要なデータを消去しない

明示的なデータ定義

Given I have following プロducts:
  | Name         | Sales number    |
  | Beer         | 20              |
  | Pizza        | 5               |
  | Socks        | 3               |      
  | Toilet paper | 100             |
When I look for best-selling プロducts
Then I see following プロducts:
  | Name         | Sales number    |
  | Toilet paper | 100             |
  | Beer         | 20              |
  | Pizza        | 5               |

プロ

  • 実装が簡単です(必要なデータをクリアする)

CON

  • ビジネス目標を読みにくく理解する
  • もっと脆い

フィルデータベース

using (var CONnection = new SqlCONnection(CONnectionString))
{                
    using (var deleteCommand = new SqlCommand("DELETE FROM プロducts", CONnection))
    {
        CONnection.Open();
        deleteCommand.ExecuteNonQuery();
    }

    SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM プロducts", CONnection);              
    DataSet data = new DataSet();
    adapter.Fill(data);

    foreach (var specFlowRow in table.Rows)
    {
        DataRow dataRow = data.Tables[0].Rows.Add();
        dataRow["Name"] = specFlowRow["Name"];                   
    }

    adapter.Update(data);
}

プロ

  • 統合テストの仕様(システムは2-endシステムを実行する)

結論

  • We need to create database tables prior to code (data-driven apプロach)
  • Slow
  • Brittle
  • Hard to implement

リポジトリスタブ

// or get stubbed repository from DI framework
プロductsRepository = new InMemoryプロductsRepository();            

// or use specflow assist helpers
foreach (var specFlowRow in table.Rows)            
    プロductsRepository.Save(new プロduct(specFlowRow["Name"]));

プロ

  • 最初にコードを実行できます
  • 高速
  • 壊れにくい(変更しやすい)
  • 実装が簡単

結論

  • We do not have プロofs that feature is implemented

それは可能な方法の私のビジョン:) どのような方法であなたは「与えられた」ステップを定義し実装しますか? ありがとう!

2

2 答え

私たちはあなたが言及した組み合わせによって与えられた実装を行います。 DIとさまざまな設定(このツールで簡単にできます)を使用することで、私たちはユニットテストをメモリ内で実行し、実際のデータベースとの統合テストとしてCIサーバに一度だけ強制します。したがって、パフォーマンスと徹底的なテストの両方が得られます。

あなたのデータを設定するために、私はあなたの例「明示的なデータ定義」が一番好きです。テストで使用するデータを指定すると、テストをドキュメントとして読むことができます。未知のデータストアに対して実行すると、テストが読みにくくなります。しかし、この場合にテストデータを作成する場合、製品の名前は重要ではなく、金額だけです。

これは、Builderパターンを使用して処理されます。テスト用にインポートするデータのみを指定し、Builderが他のすべてのフィールドのデフォルト値を生成するようにします。

NBuilder is a really nice tool. We are using it now for our tests and it looks very promising.

あなたのテストは次のようになります:

class Product
{
    public string Name { get; set; }
    public int Sales { get; set; }
}

[TestMethod]
public void SalesTest()
{
    var products = Builder.CreateListOfSize(4)
         .TheFirst(1)
         .With(x => x.Sales = 20)
         .AndTheNext(1)
         .With(x => x.Sales = 5)
         .AndTheNext(1)
         .With(x => x.Sales = 3)
         .AndTheNext(1)
         .With(x => x.Sales = 100).Persist();

    var result = SystemUnderTest.Execute();

    Assert.AreEqual(3, result.Count);

    Assert.AreEqual(100, result[0].Sales);
    Assert.AreEqual(20, result[0].Sales);
    Assert.AreEqual(5, result[0].Sales);
}
1
追加された
「セットアップはリポジトリ経由で直接行うことができます」という意味はどうですか?
追加された 著者 Wouter de Kort,
うんpersistメソッドは、指定した関数にマップされます。私たちはすべてのエンティティに使用する私たちのコンテキスト(偽のものとEFのものの両方)に汎用のAddObjectを持っています。
追加された 著者 Wouter de Kort,
SlowCheetahのリンクありがとう!メモリ内のリポジトリを使用して開発を進め、リリース設定ですべてを実際のデータベースに切り替えることをお勧めします。 NBuilderはとてもクールではありません。セットアップはリポジトリ経由で直接行うことができるようです。
追加された 著者 Sergey Berezovskiy,
私は、単純なインメモリコレクションでスタブを使用できることを意味しました。 Repository.Create(new Product( "Apple"、10))を呼び出すだけで、指定されたステップでリポジトリを満たすことができます。さて、NBuilderをもっと調べた後、Persist()に呼び出されるCreateメソッドを定義できることがわかります。
追加された 著者 Sergey Berezovskiy,

「複雑なオブジェクトや関連するオブジェクトに対してGivenを設定するにはどうすればよいですか?製品と販売のような質問は、あなたが指定している動作に依存しています。単一の正しい方法はありません。ところで、あなたは、このキュキュがどんな振る舞いのための文脈を与えるためにフィーチャーとシナリオのテキストを含まなかったのですが、推測するのは難しいことではありません。

あなたの「脆くない」最初の例は、ユーザーがトップセール商品とそのセールスナンバーの短いリストを見ることができるという基本的な振る舞いを追い出す良い方法を示しています。

ランク付けされた方法で表示することをディスプレイが何とか気にしていることを証明したい場合は、より明示的に指定し、販売ボリュームによって「逆ソート」していることを明確にします。または、この明示的な例は、あなたが意味することを本当に明確にするものと考えることができます。

私の通常の経験則は、セットアップを現在のシナリオでテストしたい "オブジェクトグラフ"の部分だけに制限することです。これは、テスト中のシステムの最も狭いビットに注意を引くのに役立ちます。それ以外の場合、すべてのシナリオですべてを最初から構築し続けると、テストの目的を理解することが難しい場合があります。場合によっては、親オブジェクトの詳細を気にすることがあります。場合によっては、パーツの合計をテストすることもできます。

1
追加された
キュウリとBDDの技術的な借金のブログページに「絞り込み」に関するセクションを追加しました: technicaldebt.com/?page_id = 1341
追加された 著者 Jon Kern,
答えてくれてありがとう、ジョン!あなたはそのようなシステムの狭小化のいくつかの例を挙げることができますか?前もって感謝します!
追加された 著者 Sergey Berezovskiy,