自動テストの実行結果

和田卓人氏:では、2つ目のメニューにいきましょう。1つ目、「信頼性の高い」にいきました。2つ目は、実行結果の話です。自動テストの実行結果。

自動テストの実行結果は何かっていうと、ただ単に自動テストの結果というだけではなくて、私は、自動テストの結果は情報であってほしいと思っています。データではなくて情報。情報って何かっていうと、人間に行動を促すもののことです。情報っていうのは、それを見た人間に意思決定と行動を促すというものです。

じゃあ、テストの実行結果を見た人間は何をするべきか。さっき言っていましたね。例えばプルリクエストのテスト結果だったらマージで本番、メインラインのテスト結果だったらデプロイできる。テスト結果が失敗だったら、原因を特定して直しにいかなければならないというわけですね。

とにかく、さっき言ったテストの結果に嘘がなければ、人間の行動は2択に収束していくわけです。緑であれば「前に進め」、赤であれば「コードを直せ」というわけですよね。さっきの象限とは違うところになると。プロダクトコードが正しい、テスト結果が成功ならデプロイ、マージに進めるぞ。誤っているなら、テストが失敗するなら、自分たちのコードをどこを直すか探しにいくという話です。

自動テストは信号機

ということで、自動テストっていうのは信号機なんですよね。緑は進め、赤は止まれです。赤はバグを探しにいけっていう話ですね。たぶんこれ、どうやらそのとおり信号機のメタファーとして始まっていまして。なので、伝統的に自動テストの世界では、テストの成功を緑、失敗を赤で伝えてくれます。緑だったら前に進めるし、赤だったら止まれというわけですね。

機械にとっては色で示すというのは若干わかりにくくて、機械にとっては終了のステータスコードで返すほうがうれしいので、0と1、あるいは1以上というわけですね。0だったら「進め」、1以上だったら「止まれ」というわけです。というので、CIの世界とかではよく「0」「1」でやっていますというような感じですね。人間向けの信号、機械向けの信号があると。

実はその赤のほうには、2種類あります。自動テストの失敗には2種類あって、これはだいぶ細かい話になってくるんですが、みなさんも考えてみると、「なるほど、2つあるな」と思われると思います。

Execution Errorっていうやつと、Assertion Failureっていうやつがあります。Execution Errorって何かって、自動テストの実行中にプロダクトコードのどこかから発生する実行時エラーのことです。NullPointerExceptionとかそういうやつですね。

Assertion Failureって何か。自動テストを書いていて、テスト対象を動かしました。テスト対象から結果が戻ってきて、結果のアサーションをしている期待値と、「そのとおり正しいかな? 期待値と一致するかな?」っていうところで失敗するやつ。つまり、テストコードまで制御が戻ってきて、テストコードの結果のアサーションのところで失敗するやつをAssertion Failureといいます。

この2つっていうのは、失敗した時の行動が若干異なります。Execution Errorのところは、コードのどこで失敗したかをスタックトレースとかから探しにいって、何が起こったかを推測するという話になりますね。

それに対してAssertion Failureは、失敗なく戻ってきてしまっているけど期待と違うので、何がおかしいかなっていうのを推測する。実はAssertion Failureのほうが、若干難易度が高いんですね。ボコッと落っこちているんじゃないから。なので、「なんでこれ、思ったとおりに動かんのだろうな?」と調べにいかなきゃいけないというような話です。

効果的なアサーションの重要性

ということで、アサーションの書き方っていうのは、失敗時に輝きます。失敗した時に助けになるアサーションを書いていかなきゃいけないんですね。試しに、わざと悪い例、頼りにならないアサーションを書いてみました。これもまた軽減税率のロジックだと思ってください。

レシートの税額欄のところ、reducedだから「軽減税額の合計が40であること」というようなアサーションをテストのほうで書いていますが、これは単なる論理式で書いているんです。「assertTrue」で、「reduced() == 40」。

なので、このテストが成功している時はグリーンで「前に進め」でOKなんだけど、失敗した時の情報量に問題があって、失敗した時に「trueだと思ったらfalseでしたよ」ぐらいの情報量しかない。これだと、この次の一歩が難易度高いんですよね。いざという時に「じゃあ、いくらだったの?」みたいな話になるので。

これ、テストが成功している時は、何ていうんですかね、この危うさに気づかないんですよ。失敗した時に初めて、「こいつ、頼りにならんな」と気づいてしまうので、ちゃんと書いていきましょうという話です。

例えば期待値と比較する。Javaで言うとassertEqualsっていうやつですね。となると、40を期待していたけど、返ってきたのは39だったっていうと、39と40、1ずれているから、ということはこれって切り捨てのところのロジックの誤りだなと。これが例えば、40じゃなくてnullだったとか、40じゃなくて0だったとかだと、調べるべきところが、初動が違いますよね。

こういう細かいところに、生産性の差というものが表れてきます。ここはだから、実測値が39だったのかnullだったのか0だったのかによって探すところが変わるというかたちですね。

(次回につづく)