テスティングフレームワークを使うことでTDD/BDDを実践しやすくなりますし、控えめに言っても、幾つかのフレームワークはTDD/BDDの思想の下に作られています。
ここからは、実際に幾つかのテスティングフレームワークの来歴について解説します。また、雰囲気をつかむ程度のサンプルコードを併記します。
TDDフレームワークと分類されることが多く、前回紹介したSmalltalkの「SUnit」を始祖とするテスティングフレームワークの総称です。「JUnit」「NUnit」とさまざまな言語に移植され、また各テスティングフレームワークでさまざまな機能が実装されています。
中でもJUnit 4がデファクトスタンダードになっており、実行結果のリポートファイル(XML)の形式においては多くのテスティングフレームワークに影響を与えています(CI:継続的インテグレーションなどがテスト結果を読み込む形式としてサポートしているのが、JUnit 4のリポートファイルの形式であることが多い)。
xUnitでの語彙としては次のようなものがあります。
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"))); } }
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.