連載
» 2014年03月25日 18時00分 UPDATE

いまさら聞けないTDD/BDD超入門(2):TDD/BDDの思想とテスティングフレームワークの関係を整理しよう (2/3)

[きょん,STAR(テスト自動化研究会)]

ツールとしてのTDD/BDD

 テスティングフレームワークを使うことでTDD/BDDを実践しやすくなりますし、控えめに言っても、幾つかのフレームワークはTDD/BDDの思想の下に作られています。

 ここからは、実際に幾つかのテスティングフレームワークの来歴について解説します。また、雰囲気をつかむ程度のサンプルコードを併記します。

xUnit

 TDDフレームワークと分類されることが多く、前回紹介したSmalltalkの「SUnit」を始祖とするテスティングフレームワークの総称です。「JUnit」「NUnit」とさまざまな言語に移植され、また各テスティングフレームワークでさまざまな機能が実装されています。

 中でもJUnit 4がデファクトスタンダードになっており、実行結果のリポートファイル(XML)の形式においては多くのテスティングフレームワークに影響を与えています(CI:継続的インテグレーションなどがテスト結果を読み込む形式としてサポートしているのが、JUnit 4のリポートファイルの形式であることが多い)。

 xUnitでの語彙としては次のようなものがあります。

  • 「Test」:テストケース。ソフトウェアを動かして確認する行為のこと。テストメソッドが該当する
  • 「Suite」:Testをまとめたもの
  • 「SUT」:「System Under Test」の略で、テスト対象のこと
  • 「Four Phase Test」:テストの手順を4つに分割する考え方。「Setup」「Exercise」「Verify」「Teardown」の4つに分割する
  • 「Setup/Before」:テストの事前準備をするまとまり
  • 「Exercise」:テスト対象に対して操作するまとまり
  • 「Verify」:テスト結果を検証するまとまり
  • 「Teardown/After」:テストの事後処理をするまとまり
  • 「Fixture」:テストを実行して個別の期待結果を生成するためのまとまり。往々にして「Setup」を何らかの形で特化させたものになる。ただし、Fixtureという用語が幾つかのテスティングフレームワーク(例えばNUnitとFit)では変わってしまっている
  • 「3-As Pattern」:Teardownを除いた形式として、「Arrange」「Act」「Assert」と表現することがある

 xUnitはKent Beck氏などのTDDを推進してきた人たちが自身のTDDを進めるために作ってきた歴史がありますが、xUnitそのものはTDDの思想を導くような強い制約を持っていないため、「xUnitを使うだけではTDDの思想を実現できるわけではない」という事実もあります。逆に言えば、「TDDをしなくても使いやすいフレームワークでもある」ということです。

 JUnit 4の簡単な例を次に示します。

package org.kyonmm;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
public class FizzBuzzTest {
    FizzBuzz sut;
    @Before
    public void setUpSUT(){
        sut = new FizzBuzz();
    }
    @Test
    public void sayInputNumber() {
        assertThat(sut.say(1), is(equalTo("1")));
        assertThat(sut.say(98), is(equalTo("98")));
    }
    @Test
    public void sayFizzWhenReceivedMultipleOf3() {
        assertThat(sut.say(3), is(equalTo("Fizz")));
        assertThat(sut.say(99), is(equalTo("Fizz")));
    }
    @Test
    public void sayBuzzWhenReceivedMultipleOf5() {
        assertThat(sut.say(5), is(equalTo("Buzz")));
        assertThat(sut.say(100), is(equalTo("Buzz")));
    }
    @Test
    public void sayFizzBuzzWhenReceivedMultipleOf15() {
        assertThat(sut.say(15), is(equalTo("FizzBuzz")));
        assertThat(sut.say(90), is(equalTo("FizzBuzz")));
    }
}

JBehave

 BDDを確立していく中で生まれた、Javaのテスティングフレームワークです。「BDDフレームワークの始祖」といえるでしょう。その後のBDDに強く残っている「Given」「When」「Then」「should」をAPIとして定義したのも、このフレームワークからです。TDDの誤解に対するカウンターであったり、TDDのコーチング方法論としてBDDの思想を形式知にしたテスティングフレームワークといえます。

Scenario: TDDのサイクルはRED、GREEN、REFACTORからなっています。
GREENからREFACTORを飛ばすことはありますが、REDからGREENを飛ばしてREFACTORしないのが特徴です。
これはテストなどによって保証されている範囲でのみ内部を変更することを「REFACTORING」と呼ぶという定義によるものです。
Given プロジェクトを始めるときはテストがない
When まず要求を満たすテストを追加する
And テストを実行する
Then テストが失敗して、TDDでいう「RED」になる
ストーリーファイル
package org.kyonmm;
import org.jbehave.core.annotations.*;
public class TDDCycleStep {
    @Given("プロジェクトを始めるときはテストがない")
    public void beginningProject(){
        // 処理
    }
    @When("まず要求を満たすテストを追加する")
    public void addTestForRequirement(){
        // 処理
    }
    @When("テストを実行する")
    public void runTest(){
        // 処理
    }
    @Then("テストが失敗して、TDDでいう「RED」になる")
    public void TestIsFailure(){
        // 処理
    }
}
ステップファイル
import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.configuration.MostUsefulConfiguration;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.junit.JUnitStory;
import org.jbehave.core.reporters.Format;
import org.jbehave.core.reporters.StoryReporterBuilder;
import org.jbehave.core.steps.InjectableStepsFactory;
import org.jbehave.core.steps.InstanceStepsFactory;
import org.kyonmm.TDDCycleStep;
public class TddCycle extends JUnitStory {
    @Override
    public Configuration configuration() {
        return new MostUsefulConfiguration()
                .useStoryLoader(new LoadFromClasspath(this.getClass()))
                .useStoryReporterBuilder(new StoryReporterBuilder().withDefaultFormats().withFormats(Format.CONSOLE, Format.TXT));
    }
    @Override
    public InjectableStepsFactory stepsFactory() {
        return new InstanceStepsFactory(configuration(), new TDDCycleStep());
    }
}
ストーリーとのマッピングファイル(これとは別の方法、例えばビルドスクリプトでの一括した定義も可能)

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

Focus

- PR -

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。