BDDを使用したテスト

はじめに



最近のプロジェクトでは、自動テストカバレッジに対する要求がますます高まっています。 今日、テストを書くことは単に良い形のサインであるだけでなく、コードに提示される要件の1つです。 TDD(Test Driven Development)やBDD(Behavior Driven Development)などの略語が増えており、多くの開発者がこれらの開発アプローチに厳密に従っています。

BDDはTDDの種類の1つであり、この記事でこれについて書いてみたいと思います。 より正確には、BDD自体ではなく、業界が今日提供しているフレームワークについてです。 絶対に正確な場合は、そのうちの約3つ: spockeasybおよびcucumber



TDDおよびBDD


ここでは、IT業界の著名人の記事やプレゼンテーションを参照しません。 TwitterでTDDについて語った1つのフレーズを思い出しましたが、それはTDDアプローチを明確かつ簡潔に特徴づけていると思います。 残念ながら、私はそれを逐語的に伝えることはできませんが、その意味は次のとおりです。「TDDに従うと、コードの各行がフォールンテストのおかげで作成されたことを100%確信できます」。 TDDとBDDの長所と短所について多くの議論を見たり聞いたりしましたが、a)テストを書く必要があります。

次に、BDDについて。 この現象は後に発生し、ファウラーが記事「Mocks Aren's Stubs」で主張するように、いわゆるMokistのおかげです。 一方、このアプローチはアガイル党のメンバーによって積極的に推進されており、開発者、ユーザー、システムアナリスト間の距離を最小限に抑えています。 これは、実行可能シナリオを取得することで実現されます。つまり、ユーザーを記述するスクリプトが実行可能テストに変換されます。 BDDフレームワークはこれをうまく行います。

それでは、比較に移りましょう。

すべての例で同じシナリオを説明しています。 スクリプト自体が問題を明確に説明する必要があるため、テストでカバーする必要があるソリューションである問題の説明は省略します。

この記事の著者は、BDD実装の同情の順序を上げています。



イージーブ


このフレームワークはGroovyで書かれています。 すべてのBDD実装と同様に、Given-When-Then表記をサポートしています。 継続的インテグレーション(CI)に簡単に統合できます。

スクリプトの例を次に示します。

description "This story is about sqrt optimisation algorithm"

narrative "this shows sqrt optimisation", {

as a "java developer"

i want "to know how sqrt optimisation works"

so that "that I can pass google interview"

}



before "init input and expected result",{

}



where "complete scenarios data",{

input = [[5, 10, -3, 17, 12, 1, -2, 13, -12], [5, 8, 13, 5, 21, 6, 3, 7, -2, 4, 8, 12]]

leftIndex = [2,3]

rightIndex = [5,10]

expectedSumm = [27,51]

}



scenario "find summ within two indexes #leftIndex and #rightIndex of the array #input",{

given "An Sqrt algorithm implementation",{

alg = new SqrtDecompositionSum(input.toArray(new int[0]))

}



when "calc sum between two indexes", {

actualSum = alg.calcSummBetween(leftIndex, rightIndex)

}



then "summ should be equal expected #expectedSumm", {

actualSum.shouldBe expectedSumm

}

}







テスト結果は次のようになります。

画像



ここでは、easybの最初の弱点が「上昇」します。 実際、2つのシナリオがどこから来たのかは明確ではありませんが、説明されています1。スクリプトのwhereセクションをよく見ると、2セットの入力値と期待値が準備されていることがわかります。 残念ながら、プロジェクトサイト上でもwhereコンストラクトは文書化されいませんが、少なくとも私はそこで見つけませんでした。

以下は、落ちたテストスクリプトの例です。





ご覧のとおり、結果は非常に読みやすくなっています。 actualSum.shouldBe expectedSumm



の行に注意してactualSum.shouldBe expectedSumm



。 これはシュガーであり、実際の結果で期待値をチェックするeasybを提供します。

IDEからスクリプトを実行するには、easybプラグインをインストールする必要があります。

私が注目できる2番目の欠点は、easybが2010年に最後に更新されたということです。

詳細については、プロジェクトのWebサイトを参照しください。



スポック


EasyBのようなSpockは、groovyから来ています。 Groovy / Grails開発者はそれを使うのが大好きです。 スクリプトは次のようになります。

class SqrtSumAlgSpecTest extends Specification {

Algorithm alg

def "Sqrt sums scenarios"(){

when:

alg = new SqrtDecompositionSum(input.toArray(new int[0]))

then:

outputSumm == alg.calcSummBetween(leftIndex, rightIndex)

where:

input | leftIndex | rightIndex | outputSumm

[5, 10, -3, 17, 12, 1, -2, 13, -12] |2 |5 |27

[5, 8, 13, 5, 21, 6, 3, 7, -2, 4, 8, 12] |3 |10 |52

}

}









where句よりもSpockの方が好きです。 spock.lang.Specification



仕様を作成するには、 spock.lang.Specification



から継承されたgroovyクラスを作成する必要があります。

以下は、ドロップされたテストケースの例です。





私の意見では、SpockはアナリストやQAエンジニアよりも開発者に近いですが、読みやすいです。



きゅうり


キュウリに出会ったのはごく最近のことで、実験を重ねるほどそれが好きになりました。 最初の2つとは異なり、CucumberはRubyから来ています。 JavaとC#の実装があります。

Cucumberスクリプトは、スクリプト自体と、Java、C#、Rubyでの実装という2つのファイルで構成されています。 これにより、スクリプトを実装から分離することができます。これにより、スクリプトが英語で完全に通常のストーリーテリングになるため、例を示します。



Feature: Sqrt Sums Algorithm Feature

In order to ensure that my algorithm works

As a Developer

I want to run a quick Cuke4Duke test



Scenario Outline: Sqrt Sums Alg Scenario

Given The input array <input array>

When The calc sum between <Left index>, <Right index>

Then The summ is <output summ>.



Examples:

|input array |Left index |Right index|output summ|

|5, 10, -3, 17, 12, 1, -2, 13, -12 |2 |5 |27 |

|5, 8, 13, 5, 21, 6, 3, 7, -2, 4, 8, 12 |3 |10 |52









ところで、キュウリのスクリプトは機能と呼ばれます。

そして、これが実装です



public class SqrtsumsalgFeature {

private Algorithm alg;

private int result;



@Given ("^The input array ([\\d\\s\\-\\,]*)$")

public void theInputArray(String input) {

String[] split = input.split(",");

int[] arrayInput = new int[split.length];

for (int i = 0; i < arrayInput.length; i++) {

arrayInput[i] = Integer.valueOf(split[i].trim());

}

alg = new SqrtDecompositionSum(arrayInput);

}



@When ("^The calc sum between ([\\d]*), ([\\d]*)$")

public void theCalcSumBetween(int L, int R) {

result = alg.calcSummBetween(L, R);



}



@Then ("^The summ is ([\\d]*).$")

public void theSummIs(int expectedResult) {

Assert.assertThat(result, is(expectedResult));

}

}









ここでは、スクリプトと実装ファイルの名前、および実装メソッドの名前とスクリプトのステップの両方で命名規則に従う必要があります。 つまり、一致する必要があります。 マッチングは、 Given 、@ When、 Then注釈および正規表現文字列を注釈の引数として使用することにより実現されます。

正規表現グループを使用して、実装メソッドの引数を強調表示できます。



以下は合格したキュウリのテストの例です







落ちた機能の例を次に示します







スクリプトの実装からの分離が好きです。 正規表現を使用して実装をスクリプトと混同することは誰かを混同する可能性がありますが、それらはスクリプトライターから隠されており、ほとんどの開発者はそれらに精通しているため、これを欠陥に起因するものではありません。 Javaの実装であるcuke4dukeの詳細については、こちらをご覧ください。



まとめ



記事は平均以上でした。 また、Mavenと継続的インテグレーションとの統合についても説明したいと思います。 これは今後の投稿のトピックになると思います。

実行可能なスクリプトを作成します。便利であるだけでなく、楽しいものです。



All Articles