アイスクリームコーンからピラミッドへの移行

和田卓人氏:ということで、「じゃあ、どうやってピラミッドを作っていこうか?」っていう話になるわけですね。多くの現場では、最初はアイスクリームコーンから始まります。別にそれは悪いことじゃありません。

いきなり最初からきれいにピラミッドを作れる組織ばっかりかというと、そんなことはないですよね。基本的に、難しいです。テスト容易性とは何かってわかっていないとピラミッドは最初から作れません。なので、最初は自動テストをがんばっているところで、E2Eテストのツールとかを入れてテストを自動化して、みたいなところから始まるんですよね。

問題は、これがそのまま長続きしちゃうことですね。基本的には、このアイスクリームコーンのパターンというのは初期は良いんですけど、これがずっと続くと、上に行けば行くほど不安定で開発を助けなくなっちゃうからつらいということになるんですね。

アイスクリームコーンのパターンが続く理由

じゃあ、なんでアイスクリームコーンになってしまうんだろうかっていうと、よかれと思ってアイスクリームコーンができて、よかれと思ってアイスクリームコーンが続いてしまうことが多いです。

なんでか。例えば自動テストを行う自動テストチームとかQAチームが分かれているっていう組織、けっこう多いんですよね。そうすると、QAチームがテストを自動化するのをがんばって、自動化率を高めていこうとすると、そこで使う道具が、例えばUI経由したエンドツーエンドのテストツールだったりするんですよね。

全体のテスト、自動化率は上がっていくんだけど、書かれる自動テストは全部Large Testのだから、よかれと思ってどんどん、どつぼにはまっていってしまうということになるんですね。これ、構造的な問題ですよね。

例えばQAチームが、自分たちの範囲内でベストを尽くそうとすると、むしろ全体としては悪い方向に行ってしまう。アンチパターンっていうのは、悪しかれと思って、悪くなろうと思ってやるんじゃなくて、よかれと思ってどつぼにはまっていくからアンチパターンなんですよね。

E2Eテストの過剰投資への警告

というので、チームが分かれているのとエンドツーエンドテストの自動化ツールがあるっていうのが掛け算になってしまうと、むしろ悪い結果になりかねない。悪い結果になりかねないっていうのは、傾向としてはもうレポートが出ていまして、Thoughtworksの「Technology Radar」という技術動向レポートっていうのがあります。半年に1回出ていて、毎回出てくると。読み込んだりとかしているんですけど。

最近のTechnology Radarで、Broad integration tests、E2Eテストのことです。E2Eテストが「Hold」にレーティングされました。Holdっていうのは、「やめておこう」と。

「過剰投資、やりすぎはやめよう」とか、「今ガンガン突っ込んでいったんだったらちょっと量を減らしていこう」とか、「これからやろうとしているんだったら少し考え直せというか、しっかり考えたほうがいいよ」というような温度感です。

なんでか。さっきまで言ってきたとおりなんですよね。これ、訳します。「テスト自動化への注力というのは賞賛に値するが、私たちが効果的でないと考える広範な統合テスト(E2Eテスト)に過剰投資している組織を多く見かける」。

過剰投資というのは、つまり、ユニットテストとかはいいから、とにかくE2Eテストで全部カバーすればいいんだよっていうので過剰投資すると、必要なインフラとかを全部用意しなきゃいけないし、いろんなチームがデプロイしなきゃいけないし、失敗した時にどこが失敗しているのかよくわからないし、みたいなかたちで頼りにならなくなってしまうと。

この資料は公開して共有しますので、詳しいところはそちらをご覧いただければと思います。

というので、じゃあ、アイスクリームコーンをピラミッドにしていくしかないよねっていう話になりますね。最初はアイスクリームコーンでOKです。これをどうやって動かし続けながらピラミッドにしていくか。

LargeテストからMediumテストへの移行

LargeからMediumへどう減らしていくかっていう話にまずいきましょう。Largeっていうのは、1つのマシンに収まらないテストでした。1つのマシンに収まらないテストをどうやって1つのマシンに収まるテストにしていくか。

ここでテストダブルというやつが出てきます。テストダブルっていうのは、モックオブジェクトとかスタブとかスパイとか、我々がよく呼んでいるものですね。モック、スタブ、スパイ、ダミー、フェイク、これらの定義の違いっていうのをはっきり述べられる人っていうのはそうそういないと思うんですが。そうそういないというのは、みんなグチャグチャに混乱していました。

ある人がスタブって呼んでいるのを、ある人はモックって呼ぶし、ある人はフェイクって呼ぶし、みたいなグチャグチャの混乱していた歴史を、この『xUnit Test Patterns』っていう本が大統一しました。

この本が出てきて以来、テストに使う偽物の総称としてテストダブルといいますよ。詳しくはスパイとかスタブとかモックとかフェイクがありますよ、というようなかたちで定義付けされて整理整頓されました。

そういったテストダブルっていうのは、テスト用の偽物っていうのは、そもそもテストしにくいものをテスト可能にする。例えばネットワークエラーとかディスクフルとか、そういったやつはテストしにくいんですけど、テストできるようにするし、モックは速くて安定しているんですよね。というメリットがあります。

でも注意点があって、テスト対象との結合度が高まりすぎて、実装をいじるとすぐ失敗するようなテストになってしまいがちです。テストが脆くなって、偽陽性を招く。あとは、モックオブジェクトと自分のコードが話し合って、その結果をテストでアサートしていると、結果的に自作自演になっていたりみたいなかたちがあったりするので、偽陽性と偽陰性、どっちも招いちゃう。

「あれ、これ、どっちも嘘に関するものじゃなかったっけ?」っていうので、けっこうテストダブル自体が使用注意なんですよね。使いすぎるとテストが信じられなくなっていってしまうので、注意しなきゃいけない。

テストサイズを下げるためのテストダブルの活用

じゃあ、使いどころはどこかっていう話になる。ここまで議論を整理してきて、テストダブル自体にはものすごく大事な役割が1つあるということが、新しい視点での役割が1つ見つかります。これはテストサイズを下げるっていうことなんですよね。テストサイズを下げるためにテストダブルを使える。

例えば、Large TestをMedium Testに下げるためには、つまり、1マシンに収まらないテストを1マシンに収めるには、偽物を作るんですけど。例えば「DynamoDB」を使っているロジックがあるとします。DynamoDB、絶対Amazon上にあるから絶対Largeになる。

それをMediumに下げるには、「じゃあ、DynamoDBのモックを自分で書きますよ」って言うと、「DynamoDBの仕様をあなたは詳しく理解しているんですか?」っていう話になる。妄想が入ってしまう。妄想が入ると偽陰性を招いてしまうので、みんなが作ったテストダブルっていうのを使うところがポイントなんですね。

公式とか準公式とか有名なオープンソース実装とかのテスト用の偽物の実装のことをフェイクといいます。そのフェイクを探していく。例えば、DynamoDBに対しては「DynamoDB local」とか、あとは「S3」に対して「LocalStack」とか、そういったものを使っていくことによって信頼性をそれほど下げずにテストサイズを下げることができるようになります。

「MediumからSmallへ」ということで、MediumからSmallへどうやって下げていくか。1プロセスの中にどうやってテストしたい要素が収まるようにしていくかって、これは設計の話なんですね。テストしにくいところを薄く切り離して、テストしたいところを大きく露出させることによって、テストが1プロセスの中に大きく収まるようにしていくんですけど、それは基本的には、良い設計をしていこうということになります。

例えば、最近『関数型ドメインモデリング』っていう本が出ましたけど、あれもやはり同じことを言っているんですよね。テストしたいところを、例えば入出力とかから切り離すことによって必然的に1プロセスにテストが収まるようになってきます。良い設計をしていくと、つまり低結合、高凝集の設計をしていくとテストサイズが下げやすくなるというような話です。

ということで、結果的には良い設計をすることによって初めて品質が上がる。私が一方的にファンの関係になっている咳さんっていう人がいるんですけど、「テストでは品質は上がらないですよ。テストはあくまでも品質を上げるきっかけで、品質を上げるのはプログラミングですよ」と。これを常に心に置いてやってきました。

テストって体重計みたいなもので、体重計に乗ったらやせるかっていうと、やせないんですよね。でも体重計に乗れば、今どのくらいの体重かがわかる。初めて今どのくらいかがわかる。でも、体重計に乗ればやせるっていうものじゃない。運動したり食事改善したりして初めてやせるという感じですね。

ということで、良いテストを構成する4本柱っていうのは、この『単体テストの考え方/使い方』っていう本にあるんですけど、このリファクタリングを助けるテストというのを書いていきましょうね。なるべく変化を、リファクタリングっていうのは、変化についていくためのリファクタリングを助けるテストを書いていこうという話になります。

サイズダウンをどうやっていくかっていうと、こんな感じでやっていきましょうと。基本的にアイスクリームコーンから、ここから始まります。

これをだんだんMedium×インテグレーションに下げて、そこからSmall×ユニットとか、Medium×ユニットとか、インテグレーション×Smallに下げていくというような路線を取っていくのがお勧めです、という感じです。ということで、アイスクリームコーンからピラミッドへ行く作戦が見えてきましたという感じです。

ということで、これがまとめのページです。この講演で言ってきたのは、ピラミッドはテストサイズで構成しましょう。

LargeからMediumに下げたりMediumからSmallに下げるのは、テストダブルを使うことによってアイスクリームコーンからピラミッドにだんだんだんだん成形していくというようなかたちを取ることによって、信頼性の高い実行結果に短い時間で到達する状態を長期的に維持するというようなテスト戦略を立てていきましょうという話になります。

ということで、私の講演は以上になります。ご清聴ありがとうございました。