🎉

単体テストの考え方/使い方 読みました

2023/05/13に公開

はじめに

単体テストの考え方/使い方を読みましたので、私が重要だと思った内容を私の意見と共にまとめました。
記事の対象は

  • 単体テストの考え方/使い方を読んでみようと思っているけど、どんな内容なんだろう?と考えている方
  • 単体テストを手っ取り早くいい感じに書きたい方

などです。

また、この記事は書籍のほんの一部です。他にも内容は盛りだくさんなので、興味のある方は実際に書籍を読むことをおすすめします。

古典学派?ロンドン学派?

書籍ではまず単体テストとは何たるかを定義しています。様々なテストがある中で単体テストとは以下の 3 つの条件を満たします。

  1. 単体と呼ばれる少量のコードを検証する
  2. 実行時間が短い
  3. 隔離された状態で実行される

これらの条件は曖昧であることから、捉え方によって思想が分かれます。書籍では二つの思想を古典学派とロンドン学派と呼んでいます。

例えば 1 に関しては
古典学派は「サービスとしての一つの振る舞い」と捉えます。
ロンドン学派は「一つのクラス」と捉えます。

つまり古典学派では単体テストが一つのクラスに縛られることはないです。

これによって 3 に関しても
ロンドン学派では「テスト対称システム」と「協力者オブジェクト」を隔離します。
一方で古典学派は、むやみやたらにテスト・ダブルは使用しないことが多いです。

単体テストの書き方を統一化する

単体テストを書くとき、AAA パターンなどを使用して全てのテストケースが統一されることを意識しましょう。AAA パターンは準備(arrange)、実行(act)、検証(assert)の頭文字です。こうすることで以下のメリットを獲得することができます。

  • 可読性が劇的に向上し、保守コストが下がる
  • 同じフェーズが複数存在しないので、複数の振る舞いを検証するようなことを避ける
  • ビジネスロジックのテスト(=act フェーズ)を 1 行にすることで、ビジネスロジックのカプセル化を強制できる。

また個人的には以下を意識するとより可読性が上がります。

  • システム対称クラスには統一した名前、例えば sut などと命名する
  • 各フェーズ間に空行やコメントを記載する

以上を意識すると下記スニペットのようなテストを書くことができます。この書き方が必ずしも良いかはケースによりますが、統一化することの恩恵は大きいです。

@Test
fun XXX_TEXT() {
    // Arrange
    val fake = createFake()
    val sut = TestTarget(fake)

    // act
    val actual = sut.do()

    // assert
    Assert.equal(EXPECT, actual)
}

単体テストの価値を言語化する

「価値のある単体テストが何か」を言語化することができますか?何が単体テストの価値を最大化するか考えてみましょう。
著者は以下を「良い単体テストを構成する 4 本の柱」と述べています。

  • 退行に対する保護
  • リファクタリングへの保護
  • 迅速なフィードバック
  • 保守のしやすさ

退行に対する保護
退行やバグをいかに発見できるかを示す性質。テストによって実行されるプロダクションコードが多いほど、この性質を備える。

リファクタリングへの耐性
テストが偽陽性を生み出さずに、リファクタリングを行うことができる性質。
偽陽性とは、実際には意図通りの振る舞いをしているのに、テストが失敗することを指す。テストが、テスト対象のコードの詳細と深く紐づくと、リファクタリングへの耐性がなくなる。

迅速なフィードバック
テストの実行時間が短いこと、開発サイクルで頻繁に行うことができること

保守のしやすさ
可読性、依存把握の容易さ、実行の容易さなど

まとめ

書籍は非常に分厚く文字も多いので、記事に記載していない内容もたくさんあります。
私も全て読んだわけではありません。
本記事では、書籍をある程度読んで実際に単体テストに適用してみた過程を通じて、手っ取り早く単体テストの価値を上げることができそうな、私が重要だと思う内容をまとめました。

私は本書籍を通じて、単体テストの重要性を学びました。一方でむやみやたらに単体テストを導入すれば必ずしも良いわけではないことはお分かりだと思います。この記事でも紹介したように、単体テストはそれ自体がコードです。
誰かがメンテナンスする必要があります。偽陽性が発生すれば、誰かがそれに対応する必要があります。これはその分だけ開発が遅れるリスクに繋がります。そして何より、テストの開発者がテストの重要性を低く感じることになるかもしれません。何故なら、正しい振る舞いをしているコードを書いても、テストが通らないからです。
つまり価値の低い単体テストなら、書かない方がマシなのかもしれません。

この書籍から学んだ知識が、自分とみなさんの今後の単体テストに活かせることができればと思います。

GitHubで編集を提案

Discussion