ヱビスブログ ::ユーザストーリーから始めるTDD
TDD from starting from user stories - a top-down styleを日本語でザックリまとめました。
-------------意味を明らかに取り違えているようなところがありましたら指摘してください。 TDDのルールは最初にテストを書く事だ。現実世界のプロジェクトの多くは、ソフトウェアがGUI、Web、データベースや外部システムとの依存を含んでいる。大概これらはJUnitクックブックのサンプルほどシンプルではない。プロジェクトが異なれば、TDDの実装方法も異なる。例えばテスターが受け入れテスト記述の責務を取り、開発者はユニットテストを書く。TDDer向けにユーザストーリーから始めるトップダウンなTDDスタイルを提唱したい。
ユーザストーリーから始めるTDD
What?
このプロセスにはいくつかのポイントがある:
Why? ユニットテストを書く時点で、クラスのテストすべき機能やインターフェースはハッキリとしているだろう。しかし、どのようにして必要なクラスを決めたり設計したりするのか。この答えは、ストーリーに記述されている機能にかなったクラスを作るようにするという事だ。ストーリーに記述された機能の理解に基づいてユニットテストを書く。 つまりストーリーに要件が記述されていないと、コードをどうすればいいのか、何のユニットテストを書けばいいのかが不明瞭になる。ストーリーで表された機能からテストすべきパブリックインターフェースが決まり、テストの失敗を通して解決策を見つけたり、対応するユニットテストを書く。 受け入れテストを書く事から始めるとストーリーの要件を確りと把握出来るようになり、要件を満たすシンプルな解決策を選択できるようになる。各クラスの機能を理解した上でユニットテストを書き、シンプルなコードでテストをパスさせる。これはとても自然なTDDアプローチだ。
How? Webアプリケーションであれば、Selenium、Watir、Sahi。JavaGUIアプリケーションならAbbot、WindowsフォームアプリケーションはNUnitForm、UIAutomation Frameworkは幅が広い。QTPはヘヴィだ。 テストコードの継続的リファクタリングはテストをわかりやすくし、よりビジネスに特化(DSL)させる事が出来る。RBehaveやJBehave等はビジネス価値を明確に反映させ、技術者ではない人間にも理解しやすい受け入れテストを記述出来る。 良い点と悪い点
良い点:
* テスト自動化をプロジェクト開始時から行いやすい
* 明確且つシンプルな設計、テスト可能なコード
* ドキュメントとしてのテスト Testdoxの様なツールは技術者にしか理解出来ないテストコードを技術者では無い人が読みやすいような形式に変換してくれる。RSpec等のテスティングフレームワークにはこの手の変換機能がビルトインされていて、RBehaveやJBehaveはテストそのものがビジネス特化言語で表される。これらはテストがよりビジネス価値を表現しやすく、一目瞭然で、理解しやすくなるようにしてくれる。
* 実装や設計の決定を引き伸ばす
* プログラミングの良い習慣を助成
* テストチームに効果がある 実践的な問題は、冴えたテストコードを生み出せないテスターの存在だ。この問題は開発者がより多くの機能テストを書く事で消滅する。 アジャイル計画では、ストーリーにどのくらい時間がかかるか見積もらないといけない。機能テストを始めに書いた開発者は、全てのテストがパスしたならば、ストーリーを完遂させたと自信を持って言うことが出来る。これによってより正確に見積もりが出せるようになり、リリース計画が立てやすくなるだろう。 * 素早いフィードバック、反復型リリースについては言及しない
悪い点:
* 単純にいかないこともある ストーリーによるTDDはいくつかの前提条件を必要とする。まず、良いストーリー。良いストーリーは独立していて、価値があり、見積もりしやすく、小さくてテスト可能だ。良いストーリーは開発者のビジネス価値への理解を容易にし、質問を挙げやすくする。次に、ストーリー毎のハッキリとした受け入れ定義だ。これによって開発者は受け入れ定義をテストに落とし込みやすくなる。良いストーリーはプロジェクト成功の隅石である。
* C++やゲーム、ツールセットの入手が限定される領域では困難 ツールは進化している。数年前はWebアプリケーションの機能テストを行う事は非常に難しかったが、今は結構な数のツールがある。需要は良いツールを作るように人々をドライブする。
* 機能テストの増加に注意を払わない事により、ビルドが遅くなる 時々この現実に直面するが、大体解決策が見つかる。例えば、開発中にストーリーに属する機能テストの記述と実行は可能だ。そしてコードをチェックインする前に全てのテストを走らせる。場面によってはテストを小さなグループに切り分け並列で実行する事が出来る。外部システムとのやりとりをスタブとモックを使うように再構成する事も出来るだろう。 サンプル
それではアイディアとプロセスのデモンストレーションをしよう。Webアプリケーションを開発中で、ログイン機能に関するストーリーがある。これだ:
ユーザとして、朕はWebサイトにログインしたい。すると登録済みユーザ固有の機能が使える。
このストーリーに対して、この様な受け入れ定義がある:
* Happy Path: ログイン成功
* ユーザ名かパスワードが不備
* ユーザ名かパスワードが間違っている Ruby on Railsを使ってWebアプリケーションを作るにあたり、seleniumの助けを借りる。このストーリーの受け入れテストを簡単に書けるようになる: Story "Login", %(
As a user,
I want to sign in the website,
So that I can use registered user specific functionality) do
@selenium = Selenium::SeleniumDriver.new("localhost", 4444, "*iexplore",
"http://localhost", 10000);
Scenario "user successfully login" do
Given "correct username and password" do
@selenium.start
@selenium.open "http://localhost/users/login"
@selenium.type "username", "someone"
@selenium.type "password", "password"
end
When "login" do
@selenium.click "submit"
end
Then "user logged in successfully" do
@selenium.is_text_present "Welcome, someone!"
@selenium.stop
end
end
#other scenarios...
end
ここでRBehaveを使う。Rubyのコードで受け入れ定義を記述するフレームワークだ。テストを書き終えたら、実行して失敗した事を確認する。それから、どうやってこのテストをパスさせるか考える。この時点で、UsersControllerとloginアクション、Userモデルの作成が必要になるだろう事がわかる。これで決定させて、テストを書き始める:
post :login, :name => "someone@domain.com", :password => "password"
assert_equal "Welcome, someone!", flash[:notice]
end
Usersコントローラのloginアクションが、ログイン処理を行いflashにメッセージをセットしているかをテストする。そしてアクションを考えつく:
user = User.authenticate(params[:name], params[:password])
flash[:notice] = "Welcome, " + user.nickname + "!"
redirect_to :controller => "home"
end
もちろん認証はUserモデルに委譲する。その為のテストを書く:
assert_equal users(:someone), User.authenticate("some user", "user's password")
...
end
後はauthenticateメソッドの実装をシンプルなコードで書く。今はHappyPathにフォーカスしているので、例外処理の事は気にしなくても良い。テストをさらに書く事で、コードはより堅牢になっていく。 というわけで、シンプルなストーリーでの成功シナリオの実装プロセスをプレゼンした。問題をいくつもの垂直なスライス(ここでは異なるシナリオ)に切り分けて解決した事に気付いて欲しい。一枚のスライスは、テストを最初に書き、シンプルなコードでテストをパスさせる事でフィニッシュする。こうする事で、各ステップについて大きな自信を持ち、自分たちが作り出している価値をハッキリと認識出来る様になる。 その他
* ツールサポートの欠如 * dev unit test -> add functional tests
* 開発者からテスターに機能テスト記述を抜き出す
* 開発者とテスターが並列に作業出来れば、生産性は増加するだろう(が、両者間で頻繁なコミュニケーションが必要になるので疑わしい) この問題が発生した場合、軽減させる方法がいくつかある。ある方法は開発者にいくつかの(全てではない)機能テストの記述とメンテナンスをやらせる(例えばHappyPathテスト)。開発者のビルドと統合して、コミットする前にテストがパスするかを確認する。 |
クイックサーチABOUTARTICLES最近のエントリ
TUMBLRカテゴリ管理 |