私は現在BDD/Cucumberに入っており、自分自身に問いかけます。どのレベルで使用するのが良いですか?
テストレベル(テストピラミッドから):
アプリケーションアーキテクチャのさまざまなレベルとフィールドにテストを適用できます。
私の現在の印象は:
Cucumber/BDDは、何をテストするかを制限しません。ただし、ビジネスルールとワークフローに使用するのが最適です。それらをテストするには、主に単体テストと統合テストを使用します。 UIテストはBDDで実行することもでき、そこにはユースケースがあります。しかし、私の印象は、ビジネスルールテストはUIで行わない方がよいということです。代わりに、ワークフロー(ビューの遷移など)と技術レベル(データ転送、ビューとプレゼンテーションロジックまたはサービスの間のやり取りなど)をテストするだけで維持できます。 UIと統合/ユニットレベルの両方でビジネスロジックをテストする必要があります。
では、なぜここにこの質問があるのですか?これまで読んだ内容には矛盾があります...
これが、BDDを使用してテストスイートをどのように構成およびアーキテクチャ化するかに関する基本的な質問に関するものであることがわかります。あなたのやり方は何ですか?それは私自身の実装にとって素晴らしいガイドラインになるでしょう。 BDD/Cucumberは何にどのように使用しますか? (テストレベル、アーキテクチャレベル)
「Xの動作の例を教えていただけますか?」という質問に答えることができますか?その後、BDDを実行できます。
したがって、ユニットレベルでBDDを実行する場合は、そのクラスまたはコードユニットの動作の例をいくつか考え、コードを使用してその例を説明します。そのためにキュウリを使用する必要はありません。私はGiven/When/Thenをコメントに入れるだけで十分だと思います これのように 。
シナリオや例の対象者が技術者でない場合は、Cucumberなどの自然言語ツールを使用する価値があるかもしれません。これは通常、UIを通じてエンドツーエンドで行われますが、そうである必要はありません。 Cucumberの作成者であるAslakHellesøyと、Konstantin Kudryashovのような他のさまざまな人が スタックのさまざまな異なるフレーバー *(Josh Chisholmで見られる)を使用して、信頼性と速度をトレードオフしました。
自然言語のツールを使用するのではなく、単に DSLを記述する またはSerenity BDDのようなDSLフレームワークを使用することもできます。
テスト-たとえば、統合テストまたは探索的テスト-は、まったく別の魚のやかんです。私は一般的にアンチパターンを目にしていますが、人々は完全に細かいテストを行っていますが、BDDに適合していないようで混乱しています。 BDDは実際にはテストに関するものではありません。本質的に、それは協調分析の実践であり、たまたまテストをニース副産物として生成します。
シナリオを「生きたドキュメンテーション」と考えるほうが便利だと思います。コードベースをクリーンで適切に設計している場合、シナリオや単体テストでバグを拾うことはほとんどありません。ただし、コードが何をすべきかを理解するのに役立ちます。つまり、最初にプログラマがバグを書く可能性が低くなります。
*(ビデオは「サブセカンドTDD」です。BDDは「テスト」よりも「動作」の方がより便利な単語でTDDの代わりとして開始されました。TDDは実際にはテストも目的ではないためです。)
通常、システムが顧客またはユーザーに値を提供する方法のいくつかの例を、Cucumberなどを使用して記述し、それぞれの方法の例を提供するクラスレベルの単体テストコードの一部が動作します。
たとえば、ユーザーがフォームを入力するのに検証がどのように役立つかを示すいくつかのCucumberシナリオがあるかもしれませんが、完全なルールは単体テストになります。
シナリオが多すぎる場合は、いくつかを単体テストにプッシュしてください。また、安定化してライブラリまたはサービスに抽出できるコードの領域があるかどうかも検討します。それぞれのシナリオがそのライブラリ/サービスのAPIで実行され、ビルドから除外されます。
そして、はい、私たちはシナリオでボタンのクリックなどを避けようとします。これは、コードを保守可能に保つのに役立ち(ページオブジェクトパターンも参照)、問題の解決方法に関するオプションも提供します。ボタンなどをクリックすると、選択したソリューションが記述されますが、シナリオは実際に問題を示しているはずです。
AslakのHoneycombパターンに関する注意:
Aslakは、ユーザーインターフェースがハニカム(Webブラウザー、ログ、アプリなど)の外側にあり、ドメインレイヤーが内側のハニカムの内側にあるパターンを説明しています。外側のハニカムの接着剤は、UIがドメインレイヤーとやり取りできるようにします。 彼はそれを説明します:
"Honeycomb"は、速度または信頼性の異なるさまざまなトレードオフのあるさまざまなモードで受け入れテストを実行できるようにするソフトウェアアーキテクチャパターンです。 1つのレイヤーまたは一部のみ。
(複数の側面を持つハニカム形状は、BDDの「アウトサイドイン」を反映していることに注意してください。ここでは、複数のユーザーインターフェイスがあることを認識しています。)
ハニカムパターンでは、UI(ブラウザなど)とドメインを通過するフルスタックシナリオに同じツールを使用します。実際、同じシナリオを使用しています!スタック全体を実行するものと、下位層を実行するものを選択するだけです。
ドメイン層だけよりも実際には多くの層があることに注意してください。たとえば、インメモリデータベースで実行することを選択できますが、完全なWebブラウザーです。実際のデータベースですが、APIに直接リンクされています。等..
したがって、たとえば、キュウリをすべて使用します。
これは、(TDDと同等の)クラスレベルでBDDを行うのと異なるです。
ドメイン層自体の中に、個々の責任(単一の責任の原則)を持つクラスがあります。
そのクラスがどのように動作するかを考え、その動作の例を提供することにより、優れた設計を推進し、そのクラスの価値を示し、生きたドキュメントを提供し、コードをクリーンに保つのに役立ちます...これはまさにTDDが行うことです!そこでは「テスト」という言葉を使わなかった。
クラスレベルのBDDはTDDであり、Wordの「テスト」はありません。
RSpecやMSpecなど、これを行うのに役立つツールはたくさんあります。あるいは、この方法でコードを考えて、とにかくTDDフレームワークを使用することもできます。私は時々「与えられたとき、それから」- コメントで (これはKotlinにあります)を書く:
@Test
fun `should handle multiple different date formats`() {
// Given a number of different types of date format
val input = listOf(listOf("2017-04-03 08:25"), listOf("01 Jan 2017 01:27 PM"), listOf("8/9/2016 8:15 AM"))
// When we parse the format of the dates
val formatters = input.map {DateFormatParser()(it)}
val results = input.Zip(formatters, {i, f -> i.map {LocalDateTime.parse(it, f)}})
// Then it should be able to resolve those dates.
val expectedResults = listOf(
LocalDateTime.of(2017,4,3,8,25),
LocalDateTime.of(2017,1,1,13,27),
LocalDateTime.of(2016,9,8,8,15))
Assert.assertEquals(expectedResults, results.flatMap { it })
}
JBehave(最初のBDDフレームワーク)は、この考え方を念頭に置いて、実際にはJUnit 3.Xの代替として開始されました。 Javaのアノテーションは当時存在しなかったため、JUnitは代わりに「test ...」で始まるメソッドを探しました。 JBehaveもまったく同じことを行いましたが、「should ...」で始まるクラスを探しました。
BDDとJBehaveの履歴の詳細については、 Dan Northの紹介 および私の 鉢植えの履歴の投稿 ;を参照してください。また、クラスレベルのBDDからフルスタックのBDD、現在のCucumberなどの自然言語ツールへの進化も見ることができます。
したがって、クラスレベルでもBDDを実行できます。通常、さまざまなツールを使用します。それらは同じツールである可能性があります。 (これはNUnitにあります) を使用してシナリオを実行するために、素敵な小さなDSLを作成することがあります。
偶然ではない限り(例:たまたまクラスがUIレベルで見られる興味深い動作の原因となっている場合のみ)、フルスタックシナリオとクラスレベルの例(単体テスト)は異なります。
これの主な理由は、ステップがフルスタックレベルでさまざまなシナリオにわたって再利用されることが多いためですが、クラスに取り掛かると、実際にはそれぞれ1つの責任のみがあり、残りはモックアウトされているはずです。
同じシナリオを使用して、できるだけ多くのレベルでBDDを使用しています。
最初に、関係者と一緒にシナリオを作成して検証することから始めます。
次に、シナリオを使用してバックエンドの開発を推進します(REST APIなど)。これらのテストに合格すると、ステップコードはUI開発者向けの優れたリファレンス資料として機能します。
したがって、次のフェーズは、UI開発者に同じBDDシナリオから派生したサービスレベルをコーディングさせることです。理想的には、BDDテストは、偽のバックエンドまたは実際のバックエンドのいずれかで実行できます。すべてが問題なく完了していれば、UI開発者はサーバー開発者に質問する必要はありません(前述の参照資料は、APIの呼び出しのセマンティクスに関するUI開発者の質問に答えるべきです)。
最後に、UI開発者は、サービスレイヤーを呼び出す実際のフロントエンドを記述します。繰り返しになりますが、彼らはシナリオを使用して開発を推進します。他の2つの層で使用されるSAMEシナリオ。
すべて完了したら、同じBDDシナリオを使用して3つのレイヤーすべてをテストします。
BDD/Cucumberでテストするレベルは?
私が好むワークフローでは、bddと単体テストの両方を、ネストされた2つのループで使用します SpecFlowとWatiNによる動作駆動開発
失敗するbdd/integrationtestsテストを書く
bdd /統合テストの一部として、次の失敗する単体テストを作成する
unitl bdd /統合テストに合格
次の失敗するbdd /統合テストを書く
BDDの頭字語は何を表していますか?
動作駆動開発はテスト方法論ではなく、ファーストクラスの機能としてテストを含む開発方法論です。具体的には、自動テストのスクリプトとして要件を使用します。
要件によって表現される抽象化のレベルでのテストに使用する必要があり、常にビジネス要件の言語で表現し、強制的にではなく宣言的に使用する必要があります ここにリンクの説明を入力してください 。