単体テストについての学び
この記事を書くきっかけ
開発業務の単体テストフェーズで多くの開発工数が取られており、単体テストのメリット(そもそも目的が違うようですが)をあまり理解できていなかったので、以下の呟きをしました。
単体テストというのは関数単体で行うのテストのことだと思っているのですが、単体テストのメリットってなんなんでしょう?
— マリン🌸ソフトウェア開発 (@Mariacron110) 2023年3月13日
複数の関数を結合させた状態でホワイトボックステストをした方が効率が良いと思ってしまいます。
結果的に有識者の方々から多くのご意見をいただけることになりました。
みなさんからご教示いただけたことを私なりにまとめた記事を書いて記憶に留めておこうと思った次第です。
前提
機能単位で要件定義からシステムテストまで一貫して担当者が変わらないことを前提に記事を書いていきます。
各工程で担当者が異なるケースの開発については、単体テストを省略して結合テスト担当者にテストを全て任せるということはあり得ないと思うので。
単体テストの定義
単体テストという言葉の定義にはバラつきがあるようで、主に以下の意味で使われます。
- 関数単体で行うテスト
- 機能単位で行うテスト
- 詳細設計を満たせているか確認するテスト
- 最小サービス単体で行うテスト
また、こちらのツイートから用語定義されていることを知りました。
ISO/IEC/IEEE24765の用語定義から、同一モジュール(ユニット)内の複数の関数を結合させた状態でテストしても単体テストになるため考え方としてOKかと。結合させた方がテスト容易ならば問題ないかと。あとはそれでテスト網羅性やカバレッジなどの品質目標が達成できるならば間違いではないかな。 https://t.co/8ML8fyrjTf
— Hayato@社会の歯車 (@HSwengineer) 2023年3月14日
実際に調べてみました。
↓こちらのURLからISO/IEC/IEEE で定義されている言葉の意味が検索できます。
"unit test"で検索してみると・・・
unit test. (1) testing of individual routines and modules by the developer or an independent tester (ISO/IEC/IEEE 24765:2017 Systems and software engineering-Vocabulary) (2) test of individual programs or modules in order to ensure that there are no analysis or programming errors (ISO/IEC 2382:2015 Information technology -- Vocabulary) (3) test of individual hardware or software units or groups of related units (ISO/IEC/IEEE 24765:2017 Systems and software engineering-Vocabulary)
↓Google翻訳 (一部翻訳がおかしいですが)
単体テスト。 (1) 開発者または独立したテスターによる個々のルーチンおよびモジュールのテスト (ISO/IEC/IEEE 24765:2017 Systems and software engineering-Vocabulary) (2) 分析がないことを確認するための個々のプログラムまたはモジュールのテスト またはプログラミング エラー (ISO/IEC 2382:2015 情報技術 -- 語彙) (3) 個々のハードウェアまたはソフトウェア ユニットまたは関連するユニットのグループのテスト (ISO/IEC/IEEE 24765:2017 システムおよびソフトウェア エンジニアリング-語彙)
つまり、上記の言葉の定義はいずれも誤りではないということになります。
この記事では単体テストを関数単体で行うテストと一旦定義して、メリットについてご紹介します。
単体テストフェーズを飛ばすデメリット
単体テストフェーズを飛ばすデメリット、単体テストを行うメリットについてご紹介します。
有識者の方々からのツイートを引用させていただいてます。
テストケースの増加により効率が悪くなる
まず効率は実の所落ちます。全パス通そうとすると関数毎で網羅した方がテストケースは少なくなりますね。(単体で補償すれば足し算的な分岐テストケースになりますが、結合しちゃうと指数的になりますね)
— ヒデマル (@hidemaruDaisuki) 2023年3月13日
正常系だけまずちゃちゃっと書いて機能でテストして、設計を確認するってはありだとは思います。 https://t.co/jwh5Qu6M4f
エラー発生時の原因特定が困難
大雑把に言うと、n個まとめてテストすると手間はたった1/nにしかなりませんが、エラー時にn!の組み合わせを考えなければならなくなります。個別だとnだけで済みます。
— Lyuka🌿private🏍 (@lyuka_jp) 2023年3月13日
つまり、n>2の場合は、まとめてやると(n-1)!倍手間が掛かって損ということになります。
バグの合成によりたまたま正常結果が得られてしまう危険性
一例だけあげると。
— kaznyan (@kaznyan3) 2023年3月14日
単体のバグが合成されて、結合テストでたまたま正しい結果になったら単体のバグが発見されません。
テスト自動化するなら、なおのこと単体のが効率良いですよ。
疎結合になり影響範囲を狭くできる
単体が必ずしも関数単体である必要はないけど、テストできる単位が小さくできるってことはそれだけ疎結合になるし、テストで問題が見つかった時に疑う範囲が狭くなる。
— Hiro@ラムダコード (@hiro_4455) 2023年3月14日
テストを書く手間は増えるけど、問題が発覚したあとの効率はよくなる。 https://t.co/mcBKQNE3tN
私の思い
単体テストを飛ばし、結合テストすることで感じていたメリット。
- 基本設計の考慮漏れがないことの早期検証
- 既存コードと結合することによる既存コードのバグの早期発見
- 複数の関数まとめてホワイトボックステストしても品質は担保される(という思い込み)
(3.については誤りだということが分かりました)
開発のスピード感と単体テスト
単体テストを行うことで開発のスピード感が無くなってしまうと思っていましたが、そうでもなさそうです。
詳細設計について
疎結合になるように関数設計することこそ詳細設計の最大のメリット?こちらについては別途記事を書こうと思います。
以上