TL;DR
大体の製品は、利用者がプロダクトコードを閲覧できない。
ユニットテストにおいてアサーションが失敗した理由を明記するという行動を通して、製品のエラーに対する親切な説明を促し、利用者体験を向上させるきっかけを作ることができる。
はじめに
コードを書くときに意識することの一つに「読みやすいコードを書く」ことが挙げられます。ですが、製品の利用者にとっては、コードの綺麗さは関係ありません。大事なのは操作が完了した際、またはエラーになった際に出てくるメッセージが分かりやすいことです。
これはユニットテストにおいても同じではないでしょうか?ユニットテストの利用者、つまり開発者にとって、テストが失敗した際に出てくるメッセージが分かりやすいことは重要だと考えています。
アサーションがわかりにくいとどうなるか
例えば、あなたはブログサイトを運営していて、ブログの新規投稿処理を改修するとします。
改修した結果、テストが以下の理由で失敗したら、あなたはどのように解釈しますか?
AssertionError: 2 != 1
これは Python のエラーなのですが、
新規投稿で登録される記事は 1 件なのに 2 件登録されてしまった
と読む人もいれば、
投稿したユーザの ID は 1 が正しいけど実際は 2 だった
と読む人もいるかもしれません。
ですが、私は
記事に紐づけられたタグのうち、1 件がまだデータベースに登録されていないものだったので、タグ一覧を管理するテーブルに 1 件追加するはずだが、2 件追加されている
のつもりで書いていました。
このように、単なる値の検証だけでは解釈が無数となり、テストがどういう理由で失敗しているのかを的確に開発者に伝えることは難しいことが分かります。
アサーションが雑になれば UX も雑になる
アサーションが雑というのは、前述したような「テスト実行時のエラーメッセージが不明瞭である」ということです。
アサーションが雑だと、テストが失敗した際にテストが失敗したことしか分かりません。この場合、開発者がテストコードを一から読み、どこでどういう理由でテストが失敗したのかを調査する手間が生じます。しかし、開発者はテストコードを読める環境下にあるので、アサーションが雑でも開発に支障をきたすことはありません。テストコードと開発者という関係なら困ることはなさそうです。
アサーションと同じノリでプロダクトコードを書くとどうなるでしょうか。製品と製品の利用者という関係を、ブログサイトに記事を投稿する例で考えます。
利用者が記事を書き終え、投稿ボタンを押すと何やらポップアップが表示されました。
そこには「エラーが発生しました」とだけ書いてありました。
利用者はこの後何をすればいいでしょうか。記事は投稿できたのでしょうか。投稿をやり直さなければならないのでしょうか。それとも、サポートルームに問い合わせなければならないのでしょうか。
この状況で果たして、
分からなければプロダクトコードを確認してください。
と利用者に言い放つ開発者がいるでしょうか。いないですよね。
アサーションにはメッセージを添える
Python の assert には
assert actual == expected, f"足し算の結果は {expected} を期待していましたが {actual} になっています"
PHPUnit の assertSame には
self.assertSame($expected, $actual, "●●テーブルに $expected 件登録されていません($actual 件でした)")
などと、アサーションに関するメッセージを添えることができ、テストが失敗した際にこのメッセージを表示することができます。このメッセージを利用して、ユニットテストの実行者に原因を説明し、ネクストアクションを提示することが開発者体験の向上につながり、開発スピードも上がるのではないか、と考えます。
また、同じマインドをプロダクトコードに応用すれば、エラー発生時にどのような理由でエラーが発生したのか、このエラーに当たった人は次にどうすればよいのかを、わかりやすく書こうとします。サポートルームに頼らずとも、利用者に対して親切に解決策が提示できるようになります。
まとめ
このように、ユニットテストのアサーションと UX にはどちらも体験がつきものです。製品の利用者がプロダクトコードを閲覧できないように、「開発者がテストコードを閲覧できない」という縛りをつけてテストコードを書くと、ユニットテストの開発者体験が自然に向上するのではないか、と考えます。
しかし、この縛りはテストコードを書く上で非常にコストのかかる手法ですし、開発には期限が設けられるのが常ですから、必ずしも今回紹介した手法にこだわってテストを書くのは大変なことです。
少なくとも、製品を利用する側の立場にこだわってコードを書いていければいいなと思っています。
みなさんの参考になれば幸いです。