Home > Tags > Testing

Testing

BDDについて自分なりにまとめてみた

BDDという言葉も割と人によって指すものが違うようなので「俺の中でのBDDはこうだよ」って内容のエントリ。別に絶対的なものでもないと思うので参考までに。

結論から

とりあえず結論だけ知りたい人向けに。

  • BDDにはふたつの種類がある
  • 1. TDDの言い換えのBDD(開発寄り)
  • 2. ATDD(受け入れテスト)でのBDD(ユーザ寄り)

振る舞い

BDDは振る舞い駆動開発と言われたりするように、テストという言葉のかわりに振る舞いという言葉を使う。日本語的には仕様と言うほうがわかりやすいかもしれない。

多分、BDDのイメージが掴みにくいのはこの振る舞いという言葉にあると思う。と言うのも振る舞いと言うのは、人の立場よって変わるからだ。例えば、プログラマがあるクラスを実装している時に言う振る舞いはそのクラスのメソッドとかの仕様になる。逆にユーザレベルの人が言う振る舞いはアプリケーションの要件・動作を言うだろう。

つまり、BDDという言葉はTDDからATDDの両方にかかるので文脈によって指すものがかわってくる。この辺は@t_wadaさんの言う「誰のためのテストか」を考える方がわかりやすいだろう。

TDDの別名としてのBDD

TDDにかかるBDD、つまりプログラマの為のBDDについて説明する。そもそもBDDという言葉が生まれた背景にはTDDに対する誤解がある。いわゆる「TDDのテストはテストじゃないよ」ってやつ。その誤解を避けるために生まれたのがBDD。多分「誤解を避ける」というのもあまり適切な表現ではない。と言うのもこの表現だとTDDを実践していない人の誤解を避けるために生まれた印象をうける。

実際はテストという言葉を使うことでTDDを実践する(しようとする)プログラマ自身にもよくない影響がある。例えばTDDの場合先にテストコードを書くので当然テストを書くときにテスト対象が存在しない。これは不自然だ。テスト対象がないことで、TDDに慣れていない人は「何をテストすればいいの?」と思うことも少なくない。

BDDではテストという言葉の変わりに振る舞いという言葉を使うと先程書いた。振る舞いという言葉を使うことで、テストという言葉から受ける違和感はなくなる。テスト対象が存在しなうちにテストを書くのは不自然だけど、なにかを実装する前に振る舞い(仕様)を決めるのは自然だ。

また、振る舞いに着目することでより良い設計ができるようになる。少なくとも僕はそう感じている。TDDでも先にテストコードを書くのでインターフェースに注意を向けることができるが、BDDの語彙を使うことでより実装と振る舞いを分離して考えられるからだと思う。

とは言え結局のところやることはTDDと変わらない。はたから見たら、TDDをしているのかBDDをしているのか区別つかないだろう。なのでここでひとつめの結論BDDはTDDの言い換えになる。もちろん使う言葉が違いプログラマに与える影響が違う以上、厳密にはTDDとBDDは違うものなのかもしれない。けれど個人的にはそこまでTDDとBDDの違いに厳密性を求めてないし、求める必要もないと思うので、プログラマ視点で見たときはほぼ同じという結論。

ATDDとBDD

ATDDはAcceptance Test Driven Developmentの略でAcceptance Testというのは受け入れテストのこと。TDDのよりレイヤの高いものだと思えばいい。Growing Object-Oriented Software, Guided by Testの画像がわかりやすいので拝借。

ATDDのひとつのサイクルでひとつの受け入れテストが完了し、それを繰り返すことでアプリケーションを実装していく。受け入れテストはどちらかと言えば顧客のためのテスト。受け入れという名の通り、このテストがパスすればその機能は実装が完了したとわかり、顧客の立場からすると要件が正しく実装されていること、進捗が管理しやすいなどの利点がある。

これとBDDに何が関係するのかと言うと、上で書いたようにBDDの振る舞いはユーザレベルで見たときはアプリケーションの要件・動作を指す。顧客は大抵の場合、ユーザレベルなのでこの場合での振る舞いは受け入れ条件となり得る。つまり、ATDDをBDDでやることは可能と言える。ATDDをBDDでやるメリットは、BDDでは振る舞いの言葉を使うのでより顧客・ユーザに近い言葉で受け入れテストを記述できるようになる(例:cucumberの日本語での記述とか)。

これがふたつめの結論のATDDでのBDD

ちなみにATDD自体も結構あやふやなやつで、何をテストするのかは受け入れ基準による。もし受け入れ基準が「とあるクラスに正しくメソッドが実装されていること」だとしたらどうなるか。これはややこしいけれど、ATDDのサイクルとTDDのサイクルの距離が大分近くなると思う。場合によってはTDDで書いたテストコードがそのまま受け入れ基準となり得ることもある。それでもTDDとATDDは目的が違うのでその辺は意識した方がいい。

Outside-In

BDDは上で説明したように、コンテキストで「振る舞い」が指すものが変わる。とは言え、根源となる思想はあってそのひとつがOutside-In。Outside-Inと言うのは外側から見た振る舞いを軸に内部を作りこんでいくということ。人によって見る位置が違うので「外側」がどこか変わってくる。プログラマならメソッドやクラスの外だし、ユーザならアプリケーションの外側。なので、BDDがなにかを一言で答えるとしたら振る舞いに着目して、それを軸に内側を作りこんでいくことになるのかなぁ。

再び結論

長々と書いて逆に混乱してきた人もいるかもしれないのでさくっとまとめ。

  • 結局は’誰が’、’誰の為に’、’何を’テストしているのかが重要である
  • TDDはDeveloper Testing。つまり僕達のためのもの。
  • ATDDはCustomer Testing。つまり顧客のためのもの。
  • BDDは振る舞いに着目する。状況・目的によって「振る舞い」が指すものが変わる。それに合わせて語彙も変わる。

なんちゃらDDはいっぱいあって、しかもそれらが色々な軸で交わったりしてすごいややこしい。TDD/BDD/ATDDと誰かが言った時は、大抵の場合暗黙のコンテキストがあるのでそこに気をつけよう。わからなかったら聞こう。「それは誰の為のテストで何をテストしているんですか?」

個人的にはBDDという言葉を使わないのは誰の為のテストかわかりづらいから。なので大体の場合はTDDとATDDのふたつを使うことが多い。BDDが僕達にくれたものは大きいけれど、その知見はTDD/ATDDに十分反映されている(もしくはされつつある)ので、普通にTDD/ATDDと言えばいいじゃないかって意見。BDDって言葉を使うとややこしくなるので僕は使いません。

おまえの言うBDDは間違ってる!!という人は突っ込みいただけるとありがたいです。

See also

BDDの導入 – Dan North – Digital Romanticism
ストーリーについて – Dan North – Digital Romanticism
XP Customer Testing

CoffeeScript + QUnitでTDD環境作ったよ

Rails3.1からCoffeeScriptがデフォルトで入ってるとかなんとかで、とりあえずCoffeeScriptだけで少し触ってみた。とりあえずQUnit自体もCoffeeScriptで書けるようなTDD環境を作ってみた。

とりあえず、UbuntuにCoffeeScriptをインストールするわけだけどaptの方が古いしせっかくだから最新のを触るかと思ったのでgithubからCoffeeScriptとnode.jsのリポジトリをcloneしてインストール。

$ git clone git://github.com/joyent/node.git
$ cd node
$ ./configure
$ make
$ sudo make install
$ node -v
v0.5.0-pre
$ git clone git://github.com/jashkenas/coffee-script.git
$ cd coffee-script
$ sudo bin/cake install
$ coffee -v
CoffeeScript version 1.1.0-pre

ディレクトリ構成はこんな感じ。coffeeにCoffeeScriptに入れて生成されたJavaScriptはsrcにいれるルール。test/index.htmlはQUnitの結果を見るため。test/qunitはずばりQUnitそのもの。

./coffee/hello.coffee
./src/hello.js
./test/index.html
./test/qunit/qunit.css
./test/qunit/qunit.js
./test/coffee/test-hello.coffee
./test/src/test-hello.js

CoffeeScriptは-wでファイルの変更を監視してコンパイルしなおすことができるので,以下の用に実行しておけばそれぞれ変更があったらコンパイルしてくれる。CoffeeScriptはデフォルトでfunction(){}();で囲って外部からアクセスできなくなるので,-bを付けてトップレベルにJavaScriptを生成するようにする。

$ coffee -w -b -o src/ -c coffee
$ coffee -w -b -o test/src -c test/coffee

これでテストコードもしくは本体のコードを修正すれば勝手にコンパイルするのでtest/index.htmlを見ればよい。後はもうちょい頑張ってブラウザを勝手にリロードするか,Rhinoとか使えばindex.htmlを用意しなくてもCUIでテスト結果をみれそう。

一式は以下のgistに置いた。(Qunitはライセンス見てないので外してある)
CoffeeScript+QUnit — Gist

steakのspec/acceptanceをrake statsに反映させる

どうやらsteakで対応してるみたいです(コメント欄参照)。steakのgroupに:developmentを追加すればrake statsの結果にAcceptance specsと表示されます。

結論から言うとrakeファイルを追加して以下のように書けばOK。(Rails.root/lib/tasks/statistics.rakeとかね)

task名がstatsetupなのはrspec-rails/lib/rspec/tasks/rspec.rakeでそうなっている為。cucumberでも同じ要領で大丈夫なはず。rake statsを実行するとちゃんと計算されている。

TDD Boot Campに参加してきました

これまた、割と今更なエントリ。当日は@t_wadaさんのお誘いでRubyグループのコーチ役として参加したけどあまりコーチらしいことしてないな・・・申し訳ない。

TDD Boot Camp(以下tddbc)では、午前中に @t_wada さんと Lasse氏 の講演、午後は各言語ごとにグループを作りペアプログラミング。朝から夜にかけてがっつりなイベントだった。TDDをやりたくてもやり方がわからない、やってみたはいいけど上手くいかないって人にはとてもいいイベントだったんじゃなかろうか。実際、僕も色々と得るものがあった。

とりあえず、当日のお題をあとで自分で書いたものを晒しておく。スレッドセーフ以外の仕様変更まで取りこんである。

http://github.com/ukstudio/LRUCache

これは1つのクラスにまとめてあるけど、結構複雑な感じになってきているので、CacheItemみたいな感じでもう1つ別のクラスを作ってそっちにキャッシュの保存期限とか持たせた方がいいかもしれない。仮にここからクラスを抽出するとしてこれだけテストが書いてあればそんなに苦労せずに抽出できるはず。テストがあるからこそクラスを抽出させるという変更も恐れることなく対応できる。

Fixnum#seconds_laterはLasse氏のを参考にした。個人的にStubの影響をブロックの中だけに限定させたかったので少し修正してある。あとは、Rspecの機能で言うと、subjectやカスタムマッチャを使ってる。それぞれそんなに難しくないので使ってみることをおすすめする。

最後にちょろっと感想を伸べておくと、tddbcはとても素晴しいイベントだったと思う。 @ebackyさんや、来日してくれたLasse氏をはじめ、スタッフのみなさん、今回このようなイベントを開催してくれて本当にありがとうございました。また参加された皆様からも色々な気づきを得られました。ありがとうございます。

僕はTDDでプログラマの階段を更に1歩登れたように思う。ハッキリ言って、TDDを知る前と知った後のコードにはかなりの差がある。なにより、TDDでのプログラミングは楽しい。tddbcに参加された皆様もこの楽しさを知ってもらえればと思う。

Home > Tags > Testing

Feeds
Meta
Others

Return to page top