こんにちは。コミュニケーションアプリ「LINE」のモバイルクライアントを開発している石川です。
この記事は、毎週木曜の定期連載 "Weekly Report" 共有の第 41 回です。 LINEヤフー社内には、高い開発生産性を維持するための Review Committee という活動があります。ここで集まった知見を、Weekly Report と称して毎週社内に共有しており、その一部を本ブログ上でも公開しています。(Weekly Report の詳細については、過去の記事一覧を参照してください)
「アーキテクチャ」ただいま工事中
メッセージを送受信するアプリケーションを作成していると仮定しましょう。送受信するメッセージのデータモデルは以下のように定義されています。
MessageContentModel
の示す通り、メッセージにはいくつかのタイプがあります。このとき、タイプは messageId
の先頭文字で決められるとします。(更に、この messageId
の仕様は、歴史的経緯により変えることができないことを前提にしてください。)
- "t": テキスト
- "i": 画像
- ...
- "e": 外部リソース
例えば、"t02af6d450d056" という ID の先頭文字は "t" なので、これはテキストメッセージの ID です。
ここで、ExternalResource
インスタンスのは他の MessageContentModel
インスタンスの作成ロジックは全く異なるとしましょう。その場合、MessageModel
を提供するクラス (...Dao
) も ExternalResource
とそれ以外で分けて実装することもあります。
messageId
に対応するメッセージが存在しない場合、関数 queryMessageModel
は null を返します。したがって、テキストメッセージの ID を ExternalResourceMessageModelDao.queryMessageModel
に渡すと、null が返されます。
メッセージのタイプに合わせて MainMessageDao
と ExternalResourceMessageDao
を使い分けるのは煩雑で、バグの原因にもなります。そこで、正しい ...Dao
を選択する役割を持つ MessageModelRepository
というクラスを以下のように作りました。ここで、各 ...Dao
の supports
関数は、与えられた messageId
に対応しているかどうかを Boolean で返します。
このようにすることで、MessageModelRepository
を使う側としては、...Dao
の存在を意識することなく MessageModel
を取得できます。
以下は MessageModelRepository
のテストコードです。
このテストでは、以下の動作が正しいことを確認しています。
- メッセージ ID の形式が正しくない場合は null を返し、どの DAO も使われない。
- テキスト、画像などのタイプでは
MainMessageDao
だけが使われる (Strictness.STRICT_STUBS
により保証される) - 外部リソースのタイプでは
ExternalResourceMessageDao
だけが使われる (Strictness.STRICT_STUBS
により保証される)
このテストにより、val dao = when {
のすべてのケースが網羅されています。これに加えてテストするべき点は何かありますか?
工事中専用のテスト
上記のテストは、「現在のコードが正しい」ことを証明するためなら十分です。しかし、将来の変更によるバグは検出できません。新しい MessageContentModel
とそれに対応する DAO を追加したとき、MessageModelRepository
の更新を忘れることが考えられます。その場合、新しいタイプの ID は単に不正な ID として扱われてしまうため、実装漏れのバグが見過ごされてしまうかもしれません。例えば、MessageContentModel.Foo
と FooMessageDao
を追加したときに queryMessageModel
の更新を忘れるとバグになるのですが、それは実行時にしか気付きにくいです。
これを防ぐには、以下のように「テストされた MessageContentModel
の一覧」と「定義された MessageContentModel
の一覧」を比較すると良いでしょう。
このようにすることで、新たなタイプが追加されたときに「MessageModelRepository
も更新しなければならない」というメッセージとともにテストが失敗するため、開発者は何をすればよいかが分かり、実装漏れを防ぐことができます。
一言まとめ
テストは現在のコードだけでなく、将来の変更にも対応できるとよい。
タグ: test
, completeness
, specification update