TDD/BDDの思想とテスティングフレームワークの関係を整理しよう:いまさら聞けないTDD/BDD超入門(2)(2/3 ページ)
TDD/BDDの思想に触れ、フレームワークとしてxUnit、JBehave、xSpec、Cucumber、Turnip、TestDoxを紹介する。
ツールとしての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 © ITmedia, Inc. All Rights Reserved.