logo

2023117

単体テストの目的・定義・学派・命名について:単体テストの考え方/使い方 第1部

『単体テストの考え方/使い方』(Vladimir Khorikov 著、須田智之訳)を読んでいるので、そのまとめを部ごとに書いていこうと思います。

  1. 単体テストの目的・定義・学派・命名について:単体テストの考え方/使い方 第1部(この記事)
  2. リファクタリングしやすいテストを書こう:単体テストの考え方/使い方 第2部前半
  3. ビジネス・ロジックと連携の指揮を分離すれば良いテストが書ける:単体テストの考え方/使い方 第2部後半
  4. プロセス外依存は統合テストで確認しよう:単体テストの考え方/使い方 第3部

今回は第1部「単体(unit)テストとは」についての感想と考察になります。第1部は以下の3章で構成されています。

  • 第1章:なぜ、単体(unit)テストを行うのか?
  • 第2章:単体テストとは何か?
  • 第3章:単体テストの構造的解析

2023-02-18 更新:記事のスタイルを修正しました。

本を読む前のテストに対する認識

まず前提として、本を読む前の私のテストに対する認識をまとめます。

  • 単体テストは普段から書いている
    • Python と pytest を使用
    • カバレッジは100%にしようというチームのルールがある
    • CI パイプラインに組み込まれている
  • モックの使い方にいまいち自信がない
    • 自作自演になっている気がする時がある
  • データベースのテストはやるべきか迷う
  • ラージテスト・スモールテスト、統合テスト、退行テストなどの用語の正確な意味や使い分けを知らない
  • TDD について勉強したことはない

上記のような感じで、あらためて振り返るとテストに関して自分がなんとなくやってきたことがさらけ出されてしまいました。今回の本では、私のようなレベルの読者でも引っかかることなく親切に解説されています。

古典学派 vs ロンドン学派

学びは色々とあるのですが、まず知ったのは「古典学派」と「ロンドン学派」がある、ということです。古典学派は『テスト駆動開発』(Kent Beck 著、和田卓人訳)を原点としています。ロンドン学派はロンドンのプログラミング・コミュニティで生まれたことに由来しています(p.28)。ロンドン学派は1単位のコードをテストするために、テスト対象以外の依存はモックを使うようにするべきと考えていて、古典学派は1単位の振る舞いをテストするために、単体テスト同士が状態を共有する依存に対してのみモックを使うべきと考えています(p.52)。

私の所属するチームでは明確にどちらの学派の主張を採用しているわけではありませんが、どちらかというとロンドン学派に近いように感じました。各メソッドを「1単位のコード」と見て、単体テストを書いています。モックに関してはロンドン学派ほど厳格ではないですが、例えば lib は lib で単体テストを行っているという理由で、lib の呼び出し側に対する単体テストでは lib をモックするというようなケースはしばしばあります。

著者が指摘する通り、私のコードベースでは1つをリファクタするとそのテストや周辺のテストも直さないといけないので、これは維持コストのかかる良くないテストコードなのかも、ということに気づきました。

テスト・フィクスチャ

第3章の「テスト・フィクスチャの準備」についての議論も興味深かったです。本の中ではコンストラクタを使って繰り返し同じ記述を書くことを避けることに関して、「テスト・ケースが読みづらくなってしまう」ことに言及しています(p.73)。

私はテストクラスでコンストラクタを使うことはあまり多くないですが、pytest.fixture を autouse=True にすることは多いです。コードの量を削減できる一方で、これも多用しすぎるとテストコードが読みにくくなってしまうので気を付けたいと思いました。

命名規則

命名規則に関しては以下のようなルールを設けています。前提として、テスト対象のメソッドに対して、テストクラスを1つ作るルールになっています。下記の命名はそのテストクラスのメソッド名に対するものです。

  • 正常系
    • test_success もしくは test_success_{事前条件}
      • e.g. test_success_when_hoge_is_fuga
  • 異常系
    • test_failure_{事前条件}
      • e.g. test_failure_when_hoge_is_invalid

本ではよくある(そして役に立たない)命名規則の例として {テスト対象メソッド}_{事前条件}_{想定する結果} というものが挙げられていますが(p.77)、私のチームでもテスト対象メソッドごとにテストクラスを作っている時点で、想定する結果(success/failure)や事前条件(when~)もあるので、これに該当してしまっていると思いました。

ただ、これに関しては私自身そこまで悪いとは思っていません。ルールがあるといっても、頭に test_success test_failure をつけているだけですし、この程度ならむしろ見やすくて良いと思います。しかしながら、そもそもこのテストクラスの作り方の枠組み自体が、振る舞いよりもコードの実装に目が行くものなのは確かなので、この点に関しては本の続きを読みながらより良くしていくためにどうするべきかを考えていきたいと思っています。

まとめ

以上、第1部「単体(unit)テストとは」についてのまとめと所感を拙文ながら書きました。

まだ途中ですが、読みやすく面白い予感なので、気になった方は是非本を手に取って読んでみてください!