第一回 xUnit Test Patterns の世界観
- 書いた人
- @yujiorama(id:yujiorama)
目次
- 目的
- はじめに
- テスティングパターンの一覧
- パターンランゲージ
- 読み進めかた
- マーチン・ファウラーによる本書の構成の説明
- 私の読み方
- 原著者(Gerard Meszaros)による情報源
- コミュニティによる情報源
- さいごに
目的
この連載記事の目的は次のような感じです。
- xUTP読書会で得られた知見を整理する
- xUnit Test Patterns に書かれている内容を分かりやすい形で広める
英語の壁も、難しさの壁も、読書会の有志による努力によって取り払われました。
軽い気持ちで、xUnit Test Patterns に挑戦してみましょう。
はじめに
TDD にせよテストファーストにせよ、テストコードを書くのは近代的な開発では当然の行為です。
しかし、戦略の無いままに無数に書かれたテストコードは保守が難しかったり、 仕様変更によってプロダクトコードのみが修正されテストコードの修正は忘れられてしまうなど、 資産としてのテストコードの価値はあっという間に下がってしまうものです。
私達は、テストコードを書くにあたって、その資産価値を高めるためにも、戦略や、保守可能な構成について学ぶ必要があります。
「xUnit Test Patterns」は、書名のとおりxUnitによるテストコードのパターンを解説するものです。
プロダクトコードの価値を高めるため、Gof を始めとするデザインパターンを学んだように、 テストコードの価値を高め、保守を容易にするためのパターンを学ぶことができるのが本書です。
「重い、長い、細かい」という三拍子が揃った名著ですが、賢明にも著者は本書の読み方について序文で次のように述べています。
(xUTP読書会Wikiのまとめページから引用)
Preface/Who This Book For
私はこの本を、第一によりよいテストを書きたい思っているソフトウェア開発者(プログラマー、デザイナー、アーキテクト)向けに書き、その次に開発者が何をやっているのか理解しようとしているマネージャーとコーチのために書きました。xUnitによって自動化された開発者テストと、カスタマーテストにフォーカスしています。加えて、xUnit以外の技術を用いることも考慮した、より抽象度の高いレベルのテスティングパターンにも言及しています。Rick Mugridge と Ward Cunningham は、Fit についての優れた本を記述していて、多くの同じプラクティスに言及しています。
開発者にはこの本を隅から隅まで読んでほしいのですが、一字一句読もうとするより、いくつかの章のいいとこ取りをすることに注力すべきです。開発者は、必要となったときにいつでも特定のパターンに戻ってくることができます。
マネージャーとコーチは、Part Ⅰ と Part Ⅱ に絞ったほうがいいかもしれません。特に、18章は理解しておく必要があります。この章で解説されるパターンは、開発者が働くにあたってどのようなサポートが提供できるかを解決するものです。また、マネージャーの方は3章だけでも読むべきです。
開発者たる私達としては、どんなパターンがあるのか、また、それがどんな場面で適用されるものなのかをいいとこ取りすればよいのです。
原著の裏表紙には、解説されているテスティングのパターンが簡単な説明と共にまとめられています。
私は、「著者はきっとこれをガイドとして本書を読むことを期待しているのではないか」思い、今回簡易的に訳してみることにしました。
テスティングパターンの一覧
パターン名のリンク先は、xUTP読書会Wikiの該当するページになっています。
リンクになっていないところは、本文に登場しないという意味ではなく、章として独立していないけれど言及されているパターンです。
ちなみに、xUTP読書会では、それぞれのパターンについて担当者が原文を読み、 理解を共有するため和訳したりスライドにまとめたりして、それを元に議論を するなどの活動をしてきました。
- Assertion Message
- Assertion Method の引数に、それを説明する文字列を渡す。メッセージは、Assertion の内容の確認や、Expectation の説明に使われる。
- Assertion Method
- 期待した出力が得られたかどうかを評価するためのユーティリティメソッドの呼び出し。
- Automated Teardown
- テストが生成したリソースが teardown で自動的に破壊、開放されるようにすること。
- Back Door Manipulation
- 直接的なデータベースアクセスのような方法で、テストフィクスチャーを構築したり、出力を検証する。
- Behavior Verification
- SUT の間接的な出力を捕らえ、期待する振る舞いと比較する。
- Chained Tests
- テストフィクスチャーを同じくするテストスイートから他のテストを実行させる。
- Configurable Test Double
- テストのフィクスチャーセットアップフェーズにおいて、再利用可能な Test Double の返す値や検証された値を設定する。
- Creation Method
- テストフィクスチャーのセットアップで、オブジェクトを利用可能な状態にするための仕組みを隠蔽したメソッド(Intent Revealing Names に従って命名される)を呼び出す。
- Custom Assertion
- テストに特化したオブジェクトの属性を比較するための Assertion Method。
- Data-Driven Test
- テスト毎に必要な情報を全てデータファイルに入れ、データファイルを読み、テストを実行する。
- Database Sandbox
- テスト用データベースを分割して開発者やテスターごとに提供する。
- Delegated Setup
- 各々のテストメソッドの中で Creation Method を呼び出して、Fresh Fixture を使用する。
- Delta Assertion
- テストメソッドによる動作前後の SUT の状態の差分を検証する。
- Dependency Injection
- SUT がクライアントに依存性を提供する仕組み。
- Dependency Lookup
- SUT 自身が依存するオブジェクトを使用するため、他のオブジェクトに問い合わせる仕組み。
- Derived Value
- 他の値から導出できる値の代わりに、計算した値を使う。
- Dummy Object
- メソッドが何もしないオブジェクトを SUT に引き渡す。
- Fake Object
- SUT が依存するコンポーネントをごく軽い実装だけのオブジェクトで置き換える。
- Four-Phase Test
- テストを、異なる 4 つの部分のシーケンスの並びに構造化する。
- Fresh Fixture
- テスト毎に使用するフィクスチャーを新たに生成する。
- Garbage-Collected Teardown
- テストの実行後のリソース開放を、テストコードを記述したプログラミング言語の提供する GC 機構に任せる。
- Generated Value
- テストの実行ごとに適切な値を生成する。
- Guard Assertion
- テストコード中の if 文をアサーションに置き換えることで、if 文の条件式が真にならない場合はテストが失敗するようにする。
- Hard-Coded Test Double
- 返す値や期待さあれる呼び出しをハードコードした Test Double。
- Humble Object
- 業務ロジックを環境から切り離されたテストしやすいコンポーネントに抽出する。
- Implicit Setup
- setUp メソッドで各テストで共通して使用するテストフィクスチャーを生成する。
- Implicit Teardown
- 自動化テストフレームワークによって、テストメソッドの実行ごとにリソースの後片付けのロジックを記述した tearDown メソッドを呼び出す。
- Inline Setup
- テストメソッドごとに、それぞれが使用する Fresh Fixture を、適切なコンストラクタの呼び出しによって生成する。
- Inline Teardown
- テストメソッドの後半で、結果の検証の後に明示的に teardown ロジックを記述する。
- Layer Test
- レイヤードアーキテクチャにおいてレイヤーごとに分割されたテストを記述する。
- Lazy Setup
- テストが最初に必要とするまでフィクスチャーの生成を遅らせる。
- Literal Value
- オブジェクトの属性の設定値やアサーションにリテラル定数を使う。
- Minimal Fixture
- 各々のテストに必要最小限のシンプルなフィクスチャーを使う。
- Mock Object
- SUT (system under test) の依存するオブジェクトをテスト専用のオブジェクトに置き換える。
- Named Test Suite
- 一緒に実行したいテストをテストスイートとして定義して、適切な名前を付ける。
- Parameterized Test
- フィクスチャーのセットアップと、結果の検証に必要な情報をユーティリティメソッド化したテストメソッドに引き渡す。
- Prebuilt Fixture
- テストを実行しながら Shared Fixture を別々に構築する。
- Recorded Test
- ツールによって記録したアプリケーションとのインタラクションを使って、テストを自動化する。
- Scripted Test
- テストプログラムを手書きすることでテストを自動化する。
- Setup Decorator
- テストを実行する前に共有するテストフィクスチャーをセットアップし、テストの実行後に全ての後始末をするような Decorator によってテストスイートを包みこむ。
- Shared Fixture
- 複数のテストでテストフィクスチャーの同じインスタンスを再利用する。
- Standard Fixture
- あらゆるテストで使用される基礎的なテストフィクスチャー。
- State Verification
- テストによって SUT を動かした後の状態を期待する状態と比較する。
- Stored Procedure Test
- 全てのストアドプロシージャについて自動化テストを作成する。
- SuiteFixture Setup
- 共有フィクスチャーを構築/破棄するため、自動化テストフレームワークによって最初のテストメソッドを実行する前または最後のテストメソッドを実行した後に呼び出される特別なメソッド。
- Table Truncation Teardown
- テストによって変更されたフィクスチャーを tear down によって破棄する。
- Test Automation Framework
- テストの実行に必要な仕組みをフレームワークとして提供することで、テストに特化したロジックを書くだけでテストができるようになる。
- Test Discovery
- 自動化テストフレームワークによってテストスイートとそれに属するテストを発見する。
- Test Double
- SUT が依存するコンポーネントを "テストをする場合において等価である" コンポーネントに置き換える。
- Test Enumeration
- 自動化テストにおいてテストスイートに属する全てのテストを手動でコーディングする。
- Test Helper
- いろいろなテストから利用するユーティリティメソッドを持ったテスト用ヘルパークラス。
- Test Hook
- テスト時のみ特別な振る舞いをするように SUT を変更する。
- Test Method
- 一つのテストメソッドで一つのテスト条件を検証する
- Test Runner
- テストケースオブジェクトを内包するテストスイートオブジェクトをインスタンス化し、実行するアプリケーション。
- Test Selection
- 自動化テストフレームワークが、テストの実行可否をテストの属性によって判断すること。
- Test Spy
- SUT による影響を受けた別のコンポーネントからの出力を間接的に記録する Test Double。
- Test Stub
- SUT に入力を与えるオブジェクトをテスト固有のオブジェクトに置き換えること。
- Test Suite Object
- 標準的なテストのインターフェースを実装し、関連するテストケースオブジェクトの集合を実行するオブジェクト。
- Test Utility Method
- テストに特有のロジックを隠蔽するメソッドに適切な名前を与えること。
- Test-Specific Subclass
- テストに必要となる状態を公開したり、特別な振る舞いをするようなメソッドを追加した SUT のサブクラス。
- Testcase Class
- 関連するテストメソッドの集合を 1 つのグループとして集めたもの。
- Testcase Class per Class
- SUT の 1 つのクラスにつき、1 つのテストケースクラスを用意する。
- Testcase Class per Feature
- SUT の 1 つのフィーチャー (機能) につき、1 つのテストケースクラスを用意する。
- Testcase Class per Fixture
- 同じフィクスチャーを使用するテストメソッドについて、1 つのテストケースクラスを用意する。
- Testcase Object
- 各々のテストメソッドを実行するためのコマンドオブジェクトを生成する。
- Testcase Superclass
- 再利用可能なテスト固有のロジックを抽象クラスとして定義する。
- Transaction Rollback Teardown
- テストの実行時にコミットされなかったトランザクションを teardown 時にロールバックする。
- Unfinished Test Assertion
- 不完全なテストが必ず失敗することを保証するためのアサーション。
パターンランゲージ
原著の序文の前に、本書の構成と、登場するテスティングパターンについて、パターンランゲージとして表現されている図があります。
「今読んでいる章と関連するパターンはどれ?」とか「このパターンは他のパターンとどういう関係なんだろう?」とか、 そういった俯瞰的な疑問が出てきたら、一旦立ち戻ってみるとよいですね。
読み進めかた
「それでも敷居が高い」と感じてしまう方を一押しするため、読み進めかたの例をご紹介します。
マーチン・ファウラーによる本書の構成の説明
Duplex Book(角征典さんによる翻訳 デュプレックス本)
先週、私のシグニチャシリーズの新刊が出た。 Gerard Meszarosによる『xUnit Test Patterns』だ。 Gerardとは数年間この件についてやり取りをしてきたので、内容についてはよく知っているのだが、実際の本を見てかなりショックを受けた。なにこの厚さ。883ページて。シグニチャシリーズのなかでダントツの厚さだ。
だが、『xUnit Test Patterns』は見た目ほど怖くはない。なぜなら、これは2冊の本が1冊になったものだからだ。私が『PofEAA』で使ったやり方でもある。 1冊目は物語(narrative)で、「隅から隅まで」読んでもらいたい部分だ。物語は要約を載せたものなので、あまりページ数は必要ない。『xUnit Test Patterns』では181ページまで、『PofEAA』では106ページまでとなっている。 2冊目はリファレンスで、こちらは隅から隅まで読む必要はなく(たまに読む奴もいるけど)、必要なときに読んでもらえればよい。つまり、物語を読んで全体的な理解をして本棚に置いておけば、リファレンスを探る必要のあるときに簡単に手に取ることができる、というわけだ。
そう、見た目ほど怖くないんですよ。
思い切ってハードカバーを外して、Part 1、Part 2、Part 3 それぞれを紐でくくって小冊子にする、という方法もあります。
また、e-Book (PDF版しかないですが…) なら「厚い」というデメリットは回避できるし、検索はできるしで、こちらもお勧めです。
私の読み方
内容
私がxUTP読書会に参加をするようになったのは、Part 2 の後半あたりまで進んでからでした。
とりあえず他の参加者の方が当たり前に使われている本書特有の語彙が分からない時期がしばらくありました。
そこで、xUTP読書会Wikiの Part 1、Part 2 の前半あたりのまとめを参考に原著を読むようにしました。
前半はとても丁寧に訳されている章が多いので、Wiki 7 割、原著 3 割くらいの読み方をしていたように思います。
Part 3 は自分なりに読み方が分かってきたので、わりと積極的に担当するようになりました。
心掛けとしては「和訳が間違ってても訂正してもらえるから自重せずにどんどんコミットしていこう」という心境でしたね。
媒体
私は e-Book 派です。
自宅やノート PC を持ってるときは PDF で読んだり、そうでないときは Kindle3 で読んでました。
原著も購入しましたが、今はディスプレイの台として活躍しています。頑丈です。
原著者(Gerard Meszaros)による情報源
原著を読むよりも、目的とする情報をピックアップするだけなら有用かもしれません。
きちんと確認はできていませんが、推敲前の原稿から構成されているものと思われます。
コミュニティによる情報源
xUnit Test Patternsl(xUTP)読書会
Working Effectively With Legacy Code 読書会から継続して開催されていた読書会です。
初回のほうでは「翻訳しよう!」という勢いがすごく、クオリティの高い翻訳が続くのですが、後半のパターンカタログは疲弊の後が見られます。
足掛け 3 年の長丁場で無事に完結したものの、雑然と積み重ねられた情報をどうやって 整理していくのかが大きな課題として残ってしまいました。
開発者テストコミュニティ devtesting-ja
当初はxUTP読書会の周知用に使われていた Google Group です。
「読書会で終わらせるのではなく、開発者テストに関するコミュニティとして継続していきたい」という合意の元、 日本で n 番目の開発者テストコミュニティのための Google Group となりました。
最近はわりと静かですが、開発者テストに関する疑問を解消したり、議論する場として活用されると嬉しいなとかの目論見があります。
Keyword(s):
References:[xUTP Magazine 0001号] [ぺけま]