ユニットテストを実装するときに、闇雲に作って行くのは効果が上がりにくいと言われています。私がユニットテストを実装していて、役に立ったなとか、これで安心できるなと感じたものを紹介します。
一般論として
一般論として、テストを行うときは、次のような値はユニットテストに限らずテストした方が良いとされています。
正常値と異常値
正常値が正しく動き、異常値が正しくエラー処理されるはテストして確認するべきです。
境界値
境界値は範囲内として正しく動作するか、範囲外として正しく動作するかテストするべきです。
- 取り得る値の最小値
- 取り得る値の最大値
- 取り得る値の最小値よりも1単位少ない値
- 取り得る値の最大値よりも1単位大きい値
1単位という部分は、一般的には1だと思います。ものによっては、0.1ということもあるでしょうし、10ということもあるでしょう。私はステップ値だと捉えています。
ビルトインデータの正確さ
プログラム内で何らかの方法でテーブルをもっているときに、以下の2点はテストして確認するべきです。
- 正しい情報が登録されているか
- テーブルから項目をピックアップするときに、正しい項目をピックアップできているか
役に立った例
ハッシュを実装したとき
次のようなハッシュを計算するアルゴリズムをプログラムで使う必要が出たことがありました。
- MD5
- SHA256
- HMAC-SHA
これらのハッシュが正しく動作することを確認するため、いくつかのテストデータを作りました。正確なデータまでは覚えていませんが、次のようなテストデータだったと思います。
- 空のデータ
- アルゴリズム的に切りが良い長さのデータ
- アルゴリズム的に切り側悪い長さのデータ
上記の様なアルゴを実装したプログラムは世の中に沢山あります。この場合は、そういった世の中にあるプログラムが出力する値と同じ値になっていることを確認できれば良いので、テストデータと期待値をユニットテストのコードにハードコーディングして、比較するコードにしました。
データ管理IDの生成処理
とある組み込みデータベースを内蔵するプログラムのときです。データを登録するときに、データ管理IDを自動生成します。管理IDは、64bit整数で0が無効で、1から連番生成します。
少し特殊なプログラムで、データを削除すると、そのIDを再利用するため、削除したIDを別のテーブルで管理します。
新しいデータを登録するときは、次のようにしてIDを決定します。
- 再利用IDテーブルに登録されているIDがあったら、最も若いIDをテーブルから削除して、そのIDを使用する。
- 再利用IDテーブルにIDが登録されていないときは、前回生成したIDに1を加えた値をIDにする。
- 2で生成したIDを記憶しておく。
- 2で生成したID+1が64bitの最大値になるときは、0を記憶して、次回のIDは1になるようにする。
突き詰めると、IDが一周したときには重複するようになってしまうのですが、使用する場所を考えると、一周して使われる可能性はあり得ません。その前にハードウェア的な限界が訪れます。
ですが、最大値と最小値のときに動くことは確認しておきたかったので、DB部分のモックを作り、起こりえない状況を作り出して、ユニットテストしました。
また、再利用するという処理は不安があったので、その部分もユニットテストでいくつか再利用パターン(かなり番号が飛んでいるなど)を作って、ユニットテストを行いました。
登録されていないIDが来たときに、再利用の方に入って、誤作動してしまうようなことがないかも確認しました。
途中で組み込みDBのミドルウェアを変更することがありましたが、ユニットテストで問題なく移行出来ることを確認出来ました。
ビルトイン管理テーブル
あるプログラムでハードウェアと通信し、ハードウェアから取得した情報を元に、アプリ内で持っているテーブルと照合して、その後の通信データを切り替えるというプログラムがありました。
この場合、組み込まれているテーブルに入っている情報が正しいことと、デバイスに対する正しいデータをピックアップできていることを全て確認するべきです。
ハードウェアと通信する部分のモックを作りました。モックが返すデバイス識別子を全機種+対象外機種を返せるようにしました。また、取得した情報が正しいことを確認するための、正しいデータを入れたデータセットをテスト対象とプログラムとは別に、ユニットテストコード内に組み込みました。
全機種以外に対象外機種を入れた理由
対象外機種を認識したときに、対象外として認識し、エラー処理が実行されることを確認するためです。
テスト対象プログラムとは別の方法でデータを持った理由
テスト対象のプログラムを変更したことで正しく動かなくなったときに、共通のリソースファイルを使っていたら、正しいとされるデータも変わってしまう可能性があります。
すると、間違ったデータを正しいデータとして認識する可能性があります。
それを避けるため、テスト対象のプログラムを変更しても、ユニットテスト側が持っている正しいデータには影響が出ないようにしておくべきです。
全機種入れたおかげで
全機種のデータを入れて、全機種ユニットテストを行ったことで、対象機種のどのデバイスでも正しく動くことの確証が得られました。全機種用意するのは物理的にも困難だったということもあります。
まとめ
他にも日々、助かったと思ったことは多くありました。
実際にやってみるのが良いと思います。やり始めはあまりにも当たり前をテストしているだけなので、意味がないように感じます。しかし、そのコードがしばらく経ってから、コードを変更するときに役に立ったりします。
すぐに役に立つこともあります。私の場合、リファクタリングして、内部構造を大きく変更したときに、結果が正しいことを単純なユニットテスト郡が保証してくれました。
投稿者プロフィール

- macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者
- アールケー開発代表。macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者。ObjC/Swift/C++をよく使っています。開発実務経験を基に、教育コンテンツ開発、技術書執筆、技術指導、技術セミナー講師、企業内研修講師、行政・自治体職員研修講師も行います。
最新の投稿
NoneCategorized2021.02.25ブログ統合(予定)のお知らせ
アプリ開発2021.01.09SwiftUIの2つのライフサイクル
Web開発2020.12.03Language Switcher で発生する 302 リダイレクトの修正
Web開発2020.12.01WordPressのXML Sitemapsプラグインを動かす