はじめに
この記事はTDD Advent Calendar jp: 2011 : ATNDの参加記事です。
私で21日目に突入しました。20日目は、haru012さんの
Testing と 私と 苦い出来事
でした。体験談かぁー。私も炎(ry ごほんごほん。
てな感じで、今までの記事では、TDDの色々がとてもお勉強になるお勧め記事がたくさんでしたが、私のはちょっとだけ業務アプリケーション開発の実作業に近づいた内容かもしれません。まぁ、実際の所、私はこんな風に思ったよ、というのが正しいのですけれども。
MVCとTDD、それぞれの利点
MVC(Model-View-Controller)と呼ばれるデザインパターンが流行ってます。実際、私も使ってます。MVCって何?って方は以下など読んでいただいて。
読んで字のごとく、MVCはアプリケーションの構造をModelとViewとControllerという3つの概念に分けるものなのですが、これらの開発過程でTDDを生かして進めていくとかなり有効。というのも、それぞれの利点がうまく重なっているんです。
まず、私が考えているMVCの利点は次のような所。
- MVCそれぞれにクラスが独立していて、作成するコードの単位が明確である。
- メソッド単位、アクセサ単位で処理を隠ぺいできるので、既存コードへの影響が少ない修正作業、リファクタリングをすることが出来る。
そして、TDDの利点は次のような所。
- 仕様が理解できているか、抜けが無いか、自己確認が出来る。
- リファクタリングや仕様変更によるデグレードを防ぐことが出来る。
- メソッド単位、クラス単位の小さなテストコードを積み重ねるので、全体がどれくらいで、今できているのがどれくらいなのか判り易く、進捗を取りやすい。
つまり、それぞれの利点の共通点は、
プログラムコードにしろテストコードにしろ、実際に作業する単位が小さい。
こと。ここ、以外と大事。独りでちまちま作るにしろ、チームで作業を分けあうにしろ、TDDで作り上げていくMVCのアプリケーションは、小さな単位を積み上げていくってことが同じだから作業に無駄がない。実際に、たくさんのテストコードがGreenになるのは楽しいし<結局そこか(笑)
効率良いTDDをするために
小さな作業単位を積み上げていくのは良いけれど、それらをもっと効率的に確実にできる方法はないのでしょうか?
例えば、チームでMVCそれぞれを担当して並行してすすめる、とか。恐らくは「独立したテストコード」を作成できれば、その理想に近づく事は出来ると思うのですけれど……。
MVCは独立しています、といっても、それぞれのクラス、メソッドで動作するプログラムは動作の前提条件や変数の内容などで密接な関係があることに違いありません。こっちが出来てないと、データこないじゃん、データないじゃん、ということはフツーにあるわけで。
そこで、テスト用クラス、Mockというクラスの考え方が出てきます。
極論、Modelのクラスを作成したい時には、Modelクラスだけがテスト出来れば良いわけです。その他のViewクラスやControllerクラスが、未実装だったり、まだバグがある状態だだったり、そんな状態で使っていたら、本来のModelクラスのテストはいくら頑張っても効率が上がらない。だから、その対策として、Modelクラスの目的の動作に必要な前提条件、テストデータ、それらを備えたクラス、Mockクラスを用意するのです。それを使う事で、前提条件がそろった状態で実行できますから、自分は必要な最低限のModelクラスの動作だけをテストコードに記述すればよいですね。
具体的に、データベースからレコードを取得して一覧に表示する、を例に考えると、
- データベースからデータを取得する。
- 一覧表示用のリストデータに加工する。
- リストデータから一覧表示を行う。
とMVCの単位で大まかに分けることができます。実際にはもっと色々とあるかもしれないけど、例なので大雑把(笑)。この時にTDDしよう!と思ってテストコードを書き始めた時、1を作って動作できたら、2を作って、2が動作出来たら3を作る、とやっていかないと、必要な前提条件(データ)がそろわない。
でも、
- データ取得ためのデータを提供するデータベースのMock
- リストデータ加工するためのソースデータを持つクラスのMock
- リスト用データに加工済みのデータを提供するクラスのMock
がそれぞれにあれば、1~3のクラスを並行に作業可能。自身以外の必要なクラスはMockに任せてしまってるから、本当に自分が作りたいクラスとメソッドの動作を検証するだけのテストに特化でき、TDDのサイクルも早くなります。
つまり、Mockクラスを使う事で「独立したテストコード」が可能になるんです。
ちなみに、実際にテスト用Mockを使ったテストを行う時、良い仕事をしてくれるのがInterfaceクラス。Mockに置き換えたいクラスがInterfaceを持つことで、呼び出し側はMockなのかそうでないのか、意識する必要がなくなります。DI(Dependency Injection)できるフレームワーク上でのTDDなら、なおのこと、必要に応じてMockを注入できるからお勧め。
TDDの肝
こうなってくると、Mockを作成する=Mockの内容に仕様と齟齬があったら、なかなか大変なことになるのでは?と思いませんか?
Mockの作成もさることながら、テストコードの作成にしてもそうです。テストコードの品質=作成されるアプリケーションの品質、と考えても過言ではないでしょう。あくまでもこれは経験則ですが、TDDの肝は、言語やフレームワークに関係なく、まず仕様の理解が必要不可欠であり、それをいかにテストコードに反映できるか、だと思っています。なんて偉そうに言ってても、まだまだ私も修行中の身、仕様理解できてない、勘違いしてた、がよくあってorz。
TDDは小さな単位でプログラムコードの動作を検証でき、それを積み上げていくことで磨かれていく開発手法です。MVCパターンとも相性がよく、うまく使えば非常に有効な手段でもあります。
というわけで、私の記事は終わりです。最後に、TDDに携わるようになってから覚えた、自戒の意味をこめて、この言葉を。
「書いていないテストコードにバグがある」