[ブログ紹介] BDD の導入 - Dan North
BDD ( Behaviour-Driven Development : ふるまい駆動開発 ) の提唱者である Dan North 氏の記事の翻訳です。
Digital Romanticism - digitalsoul のブログ: BDD の導入 - Dan North
2009-08-19この記事は Dan North 氏の記事 「Introducing BDD」 を氏の許可を得て翻訳した公式版 ("the official translation") です。 (原文公開日:2006年9月20日)
Dan North 氏は、 ThoughtWorks 社で働いていた 2003年頃から BDD を提唱されています。
※ 現在は ThoughtWorks 社に所属していないかもしれません。 当時所属していたことは、 O'Reilly の紹介ページ(英語) や sys-con.com の Dan North のページ(英語) の自己紹介欄などで判ります。
私自身は、 BDD ( というよりも、 NBehave を使って開発すること ) には懐疑的ですが、 BDD の考え方自体は示唆に富んでおり、 TDD の実践者はこの記事を読んでおくべきだと思います。
テストをなんと呼ぶべきかという質問の答えは簡単です。 これは関心対象となっている、 次に実装するふるまいを記述した文章です。
これは、 ほぼその通りだと思います。
100% ではないと思うのは… テストファーストで、 あるメソッドのテストを書き始めるとき、 そのテストメソッドでは、 これから作るメソッドの動的な外部仕様である、 ふるまいも記述しますが、 静的な外部仕様である、 メソッドのシグネチャ (メソッド名・引数・返値の型) をも決定するからです。 テストファーストでは、 テストを書くことで、 メソッドのシグネチャとふるまいの両方を定義しているのです。
※ ですから私は、 「ユニットテストはメソッドの外部設計である」 と思っています。
記事中のコードは Java ですが、 C# を使える人にはとくに苦になるところはないでしょう。 1点だけ…
public class ClientDetailsValidator {
private final AgeCalculator ageCalc;
public ClientDetailsValidator(AgeCalculator ageCalc) {
this.ageCalc = ageCalc;
}
}このようにしてオブジェクト同士をつなぐ方法は、依存性注入("dependency injection")と呼ばれており
「AgeCalculator ってコンクリートクラスを受け取っておいて、 どこが DI だよ~!?」 と勘違いしないでください。 Java ではインターフェースの名前の頭に 'I' を付ける習慣が無いだけで、 この AgeCalculator はインターフェースのはずです。
記事では Java 用の BDD フレームワーク JBehave が紹介されています。 他の言語にも移植されていて、 .NET Framework 用として NBehave の開発が進められています。 ( 現在、 ver. 0.4 )
・ http://nbehave.org/ (英語)
・ http://www.codeplex.com/NBehave (英語)
ここで記事から離れて、 CodePlex に掲載された NBehave のサンプルを少し見ておきましょう。 まず、 ストーリーとシナリオを次のように記述します。
Story: Transfer to cash account
Narrative:
As a savings account holder
I want to transfer money from my savings account
So that I can get cash easily from an ATM
Scenario 1: Savings account is in credit
Given my savings account balance is 100
And my cash account balance is 10
When I transfer 20 to cash account
Then my savings account balance should be 80
And my cash account balance should be 30
Given my savings account balance is 400
And my cash account balance is 100
When I transfer 100 to cash account
Then my savings account balance should be 300
And my cash account balance should be 200
Given my savings account balance is 500
And my cash account balance is 20
When I transfer 30 to cash account
Then my savings account balance should be 470
And my cash account balance should be 50
このあと 2通りのやり方があるそうですが、 そのうちのひとつ 「テキストファイルとアクションステップによる方法」 を見てみます。
シナリオごとにテキストファイルに保存し、 NBehave-Console.exe を使ってシナリオをコンパイルしておきます。
続いて、 アクションステップ (ActionSteps) クラスを記述します。 これは、 シナリオの各行を実際のクラス呼び出しに変換するメソッドの集まりです。
再び nbehave-console.exe を走らせると、 アクションステップを通じてシナリオを実行しようとします。 ( まだ実装クラスが出来ていないので、 失敗します。 )
このあとは、 実装クラスを書いてみては nbehave-console.exe を走らせることを繰り返して、 実装を完成させていきます。
考え方は理解できるのですが、 シナリオを書いてアクションステップを書くという手順は、 私にはどうにもまどろっこしいのです。 上に引用したシナリオは、 Visual Studio の単体テストとして書き下すならば、 私は次のように書くでしょう。
/// <summary>
/// Story: Transfer to cash account
/// Narrative:
/// As a savings account holder
/// I want to transfer money from my savings account
/// So that I can get cash easily from an ATM
///</summary>
[TestClass()]
public class AccountTest_TransferToCashAccount
{
[TestMethod()]
[Description("Scenario 1: Savings account is in credit")]
public void SavingsAccountIsInCreditTest()
{
{
// Given
Account mySavings = new Account(100);
Account myCash = new Account(10);
// When
mySavings.TransferTo(20, myCash);
// Then
Assert.AreEqual<decimal>(80, mySavings.Balance);
Assert.AreEqual<decimal>(30, myCash.Balance);
}
{
Account mySavings = new Account(400);
Account myCash = new Account(100);
mySavings.TransferTo(100, myCash);
Assert.AreEqual<decimal>(300, mySavings.Balance);
Assert.AreEqual<decimal>(200, myCash.Balance);
}
{
// ・・・
}
}
}
このように、 直接テストコードとして表現できるものを、 わざわざ二度手間掛けて作業する必要があるのか、 私はそこを疑問に思うのです。
| 固定リンク
「ブログ紹介」カテゴリの記事
- [ブログ紹介] Writing Unit Tests in F#(2011.11.09)
- [ブログ紹介] VS と連携 *しない* NUnit の使い方(2011.08.01)
- [ブログ紹介] 三角形問題で必要なテストケース数(2011.06.08)
- [ブログ紹介] CppUnit を Visual Studio C++ 2010 でビルドするには(2011.06.06)
- [ブログ紹介] TDDBC ポータル (Hiki)(2011.03.11)
この記事へのコメントは終了しました。
コメント