MyEnigma

とある自律移動システムエンジニアのブログです。#Robotics #Programing #C++ #Python #MATLAB #Vim #Mathematics #Book #Movie #Traveling #Mac #iPhone

良いUnit testの書き方


Googleのソフトウェアエンジニアリング ―持続可能なプログラミングを支える技術、文化、プロセス


レガシーコード改善ガイド (Object Oriented SELECTION)

目次

はじめに

これまでも各言語のUnit testのフレームワークなど、

Unit testの作り方を説明した記事はまとめてきましたが、

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

 

どのような (どのように)Unit testを書くべきか(設計すべきか)という資料は

あまりまとまっていない気がしたので、

これまで自分が読んで来た冒頭の書籍や、

自分の経験を元にまとめておきます。

 

Unit testは速いほうが良い

開発の途中で何度も実行しても、苦にならないように、

ユニットテストはできるだけ、速く実行できる方が良いです。

Unit testは安定していないといけない

ランダムにfailするUnit testほど辛いものは無いので、

バグを見つけれてくれるメリットよりも、

ランダムfailするコストを考えると、

そのようなテストは消すか、integration testに移動させたほうが良いかもしれません。

Unit testは環境に依存してはいけない

前述の安定化のために、Unit testは環境に依存しない方が良いです。

環境変数や、テストを動かす計算機のリソースに依存した

Unit testは書かないほうが良いでしょう。

Unit testが外部のシステム(DBや通信による別のアプリ)に依存してはいけない

前述の安定化のために、Unit testは外部システムに依存しない方が良いです。

特に、DBにアクセスしたり、外部システムに通信するようなテストは

Integration testとして実装すべきでしょう。

公開APIを使ってUnit testを作成すべき

Unit testは外部のユーザに公開されている公開APIを使って作成したほうが、

後のソフトウェア変更に強い(Unit testのメンテナンスが少ない)テストにできます。

これは、公開APIはすでに他のユーザがいるため、

APIの変更があまり頻繁に実施されにくいからです。

一方、非公開APIは、リファクタリングなどで頻繁にAPIを変更したくなるはずなので、

非公開APIに対するUnit testは脆くなる傾向があります。

しかし、非公開APIでも、入出力が明確に決まるものに関しては、

脆くないUnit testを書けるので、適宜判断が必要です。

二箇所以上の場所で使われていたらテストする

無限のリソースがあれば、

すべての公開APIにUnit testを書くべきですが、

大抵リソースは限られているので、

どのAPIにUnit testを書くべきかどうか悩む場合は、

コードベースの中で二箇所以上の場所で使われていたら、

Unit testを書くという方針を取ることが多いです。

これは二箇所以上で使われている場合は、

今後も使用箇所が多くなることが多いからです。

テストコードの本体は読んで一瞬でわかるように、明確なテストを書く

コードをテストすることは重要ですが、

同じぐらい何がテストされているのかをわかりやすくすることも重要です。

その一つとして、テストコードを見た時にAssert文で何をテストしているのかを

わかりやすくするようにコードを工夫することも重要です。

テスト関数名は長くても良いので明確にわかりやすい名前をつける

何をテストしているのかを明確にわかるような

テスト関数名(多少長くても良い)をつけることも有用です。

テスト関数名はShouldから始めると、挙動や状態をテストする時に、

わかりやすいテスト関数名になりやすいと思います。

テストはメソッド毎ではなく、挙動や状態でテストする

Unit testを書いていると、書くメソッド毎に書いてしまいがちですが、

システムの挙動や状態毎にUnit testを書くと、

テストの内容が理解しやすく、

複数のメソッドコールを含めたシステムの挙動をテストできるので、

コード量の少ないテストで網羅的にシステムをテストできます。

テストコードはgiven, when, thenで分類する

他の人が読んでわかりやすいテストコードを書く方法として、

ビヘイビア駆動開発で提唱されているように、

en.wikipedia.org

Given, When, Thenでテストコードを分類してコードを書くと、

読みやすいコードになります。例えば

# Given 
システムの前提条件を設定

# When
ある特定の状態を設定

# Then
アサート文でテスト

のように、コードのブロックをGiven, When, Thenで書くと

Unit testのコードが一気にわかりやすくなります。

多少重複があってもテストは愚直に書く

一般的なコードではDRY(Don't Repeat Yourself)の原則で、

重複したコードをできるだけ無くすことが多いですが、

テストコードの場合は、あまりコードを断片化しすぎると、

様々なコード部分を読みに行かないと、テスト内容が把握できなくなるので、

多少の重複があったとしても、一つのテスト関数だけを見れば、

テスト内容がわかるようにするほうが良いと感じるようになりました。

エラーメッセージはわかりやすく書く

Unit testのもう一つ重要な点として、

テストがfailした時に、なぜそのテストがfailしたかをわかりやすくするように、

エラーメッセージを工夫したほうが良いです。

これにより、テストコードの詳細を確認しなくても、

自分の変更の問題や、テストコードの修正方針を

即座に理解することができます。

Builderパターンで初期オブジェクトを作り、その一部を変えてテストを書く

Unit testを書くときに、ある一つのベースとなるオブジェクトを作る関数を作り、

そのオブジェクトの一部を変えて、各テストを作成すると

一貫性のあるテストを書くことができます。

デフォルト引数の機能がある言語では、デフォルト引数を使えば良いですし、

Javaのような言語ではBuilderパターンを使うと、

簡単にデフォルトオブジェクトを作ることができます。

qiita.com

 

アサートするときに、計算された値にはactual, 期待する値にはexpectedをプレフィックスとしてつける

これにより、コードが読みやすくなるなります。

 

テストではハードコードした値を勇気を持って使う。

あまり変数とかを使うと、テストでは読みにくくなったりするので、

勇気を持って、ハードコードを使った方が良いことが多いそうです。

 

参考資料

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com


レガシーコード改善ガイド (Object Oriented SELECTION)


レガシーコード改善ガイド (Object Oriented SELECTION)

 

MyEnigma Supporters

もしこの記事が参考になり、

ブログをサポートしたいと思われた方は、

こちらからよろしくお願いします。

myenigma.hatenablog.com