Skip to content

Instantly share code, notes, and snippets.

@denvernine
Last active July 28, 2023 03:20
Show Gist options
  • Select an option

  • Save denvernine/5f0f5692d9164ded7497daea276e37c8 to your computer and use it in GitHub Desktop.

Select an option

Save denvernine/5f0f5692d9164ded7497daea276e37c8 to your computer and use it in GitHub Desktop.
『単体テストの考え方/使い方』を読んだ
original:
author: Vladimir Khorikov
title: Unit Testing Principles, Practices, and Patterns
publisher: Manning
published_on: Jan, 14, 2020
isbn13: 9781617296277
ja:
訳者: 須田智之
題: 単体テストの考え方/使い方
出版社: 株式会社マイナビ出版
出版日: 2022年12月28日
版: 初版第1刷・電子版ver1.00
isbn13: 9784839981723

第2章

  • 単体テストを「少量のコード(1単位のふるまい)」を「短い実行時間」で「(他のテストケースから)隔離された状態で実行される」ものと定義する
    • 8章の先取りになるが、統合テストは上記の定義に あてはまらないテスト ということになる
  • デトロイト学派は古典主義で、本番コードと同じように依存クラスなどを準備する
    • 共有依存関係であるDBなどはモック化する
  • ロンドン学派はモック主義で、依存クラスはすべてモック化する
    • Enumやconstは不変のためモック化しない
  • pp44-45の図が参考になる

デトロイト学派的隔離: p37

  • テストケース同士を隔離すること
    • 1つのふるまいを隔離する
  • テストケースの干渉を防ぐためにプロセス外依存(DBなど)をモック化する
    • 依存先クラスなどはモック化しないでプロダクションコードをつかう
    • プロセス外依存を モック化しない テストはIT(Integration Test、統合テスト、結合テスト)などより上位のテストで行う
    • ロンドン学派からみると統合テストのようにみえる
  • バイブルは『テスト駆動開発』 12

pros

  • 大きなまとまりとしての動作は検証しやすい

cons

  • 依存関係の解決が大変
    • 依存クラスの依存クラスの依存クラスの……依存クラスを用意しなければならない
      • その場合はそもそもの構造が問題であることもある

デトロイト学派的統合テスト

  • 上述した単体テストの定義から外れるテスト
    • 2つ以上のふるまいを同時にテストする場合
    • 時間がかかるテストの場合

ロンドン学派的隔離: p29

  • テストケースと依存先を隔離すること
    • 1つのクラスを隔離する
  • 隔離のためにモックを多用する
    • たとえば、依存先のクラスはすべてモック化する
  • バイブルは『実践テスト駆動開発』 34

pros

  • 1クラス1テストなので問題個所の発見が簡単になる
    • 1テスト≠1テストケース
  • 依存関係の解決が(比較的)簡単
    • 全部モック化するので

cons

  • テストコード量が増える
  • プロダクションコードとの結びつきが強い
    • モック化するので、振る舞いの再現のためにコードの詳細を知る必要がある
      • プロダクションコードの依存先が変わるとテストコードも修正しなければならない
        • テストコードの書き方によってはデトロイト学派でも同じな気もする
  • モック化することで保守性が下がる
    • プロダクションコードに変更があってもモックは変更されないので、既存コードのテストは通ってしまう
      • テストコードの更新忘れがあっても気づくのが遅れたりする
    • テストコード→プロダクションコードの順に修正すればそれで解決する?

ロンドン学派的統合テスト

  • 依存先クラスをモック化せずにするテスト

感想など

著者的にはデトロイト推し?デトロイト学派スタイルの利点が詳細に書いてあるのに対して、ロンドン学派スタイルは問題点や課題のほうが詳細に書いてある印象を受ける。

Footnotes

  1. Kent Beck, Test-Driven Development: By Example, Addison-Wesley Professional, 2002

  2. 和田卓人訳, テスト駆動開発, オーム社, 2017

  3. Steve Freeman and Nat Pryce, Growing Object-Oriented Software, Guided by Tests, Addison-Wesley Professional, 2009

  4. 和智右桂 髙木正弘訳, 実践テスト駆動開発, 翔泳社, 2012

第4章

理想的なテスト: p96

  • A: 退行(regression)に対する保護: p96
    • 退行とはバグのこと
    • なんらかの変更(機能追加など)があっても既存の機能が意図したように動いているほど保護されている
      • テスト時に実行されるプロダクションコードの量を少なくする
      • プロダクションコードの複雑度を小さくする
      • プロダクションコードの扱う重要度を小さくする
  • B: リファクタリングへの耐性: p98
    • テストが失敗することなくプロダクションコードのリファクタリングを行えるか
    • 偽陽性の発生が少ないほど耐性がある
      • 正しく(期待通りに)リファクタリングした結果、テストが失敗するようになることを「偽陽性」と呼ぶ
  • C: 迅速なフィードバック: p113
    • テストを速やかに行えること
  • D: 保守のしやすさ: p113
    • 保守コスト
    • テストケースの理解困難度
    • テストの実行困難度

テストケースの価値: p114

  • テストの価値 = A{0..1} * B{0..1} * C{0..1} * D{0..1}
    • いづれかの要素が0になったとき、そのテストケースの価値は0になってしまう
    • 理想的なテストケースはすべての要素の度合いが1になっていることだが、そのようなテストケースを作ることはできない
      • A, B, Cの3要素は互いに排反であるためである
        • ABを1にするとCは0になってしまう
          • e.g.) E2Eテストだけでは迅速なフィードバックを得ることはできない
        • BCを1にするとAは0になってしまう
          • e.g.) 取るに足らないテスト(プロダクションコードと同じことを別の書き方で表現しているだけのテスト)では何も検証していないも同然で、退行に対する保護は全く備わっていない
        • ACを1にするとBは0になってしまう
          • e.g.) 壊れやすいテスト(プロダクションコードをリファクタリングすると失敗するようになるテスト)にはリファクタリングへの耐性がない
      • p120の図が参考になる

実現可能なテストケースのうち、もっとも理想に近いテストケース: pp120-122

  • B, Dを1とし、A, Cでバランスを調整する
    • 退行に対する保護と迅速なフィードバックのどちらかを多少犠牲にするということ
      • この感覚はデータストアなどで使われる「CAP定理」というものに似ているらしい
    • テスト・ピラミッドにあてはめると、以下のようなバランスとなる
      • 単体テスト: A{.3} * B{1} * C{.7} * D{1}
      • 統合テスト: A{.5} * B{1} * C{.5} * D{1}

CAP定理: p123

  • C, A, Pのうち同時に保証できるのは2つまでだという考え方で、一般的にRDBMSはCA、NoSQL/分散データベースではCPまたはAPを選択する

    • Consistency: 一貫性
    • Availability: 可用性
    • Partition-tolerance: 分断耐性

    CA分散データベースについては、理論上の検討を行うことはできても、実際的には存在しないと言えます。
    -- CAP定理の概要 | IBM

    • DynamoDBはNoSQLらしくAPデータストアになっている

    アマゾンの経験では、ACID(Atomicity(原子性))、Consistency(一貫性)、Isolation(独立性)、Durability(永続性))を保証するデータストアは高可用性が維持できない。これは産業界でも学会でも広く認められていることだ。Dynamoでは高可用性につながるならば、一貫性を多少犠牲にしても運用できるアプリケーションをターゲットにしている
    つまり、いかなる場合でも顧客がショッピングカートに商品を入れられるように、データの一貫性を多少犠牲にしてでも可用性を優先するというアプローチをとっているということになる
    -- クラウドの衝撃: IT史上最大の創造的破壊が始まった 1

ブラックボックステスト・ホワイトボックステスト: pp124-128

  • ホワイトボックステストでは偽陽性が多く含まれ、リファクタリングへの耐性が欠落する。また意味のある振る舞いを認識しづらくなる傾向がある。
    • よってブラックボックステストを選択(採用)するべき
      • リファクタリングへの耐性を高くするために、「実装の詳細ではなく、最終的な結果を確認する」: p106
特徴 退行に対する保護 リファクタリングへの耐性
ブラックボックステスト ソースコードなどの内部構造を知らずに検証する。仕様や要求から作成される 劣っている 優れている
ホワイトボックステスト ソースコードなどの内部構造を検証する。ソースコードから作成される 優れている 劣っている

感想など

「偽陽性」を抑えるためにリファクタリングへの耐性が必要という点は強く共感できる。

偽陽性への対処

  • 偽陽性は「実装は正しい(期待通りである)のに、テストは失敗している」状態
  • 偽陰性は「実装が間違っているが、テストは成功している」状態

ブラックボックステストを採用することでプロダクションコードとテストコードを「隔離」する。2章でも感じた(モックを多用したテストなどで発生しやすいであろう)「偽陰性」にも注意したい。

偽陽性についての文量が多く、コラムにも偽陽性によって起きた問題が書かれている。偽陽性の強い(?)プロジェクトではテストのことを考えなくなっていくという旨のことが書いてあるが、これは『レガシーコード改善ガイド』の「第24章 もうウンザリです。なにも改善できません」という部分にも通ずるところがあるのかもしれない。 23

Footnotes

  1. 城田真琴, クラウドの衝撃: IT史上最大の創造的破壊が始まった, 東洋経済新報社, 2009

  2. Michael C. Feathers, Working Effectively with Legacy Code, Prentice Hall Professional Technical Reference, 2004

  3. ウルシステムズ株式会社 平澤章 越智典子 稲葉信之 田村友彦 小堀真義 訳, レガシーコード改善ガイド, 翔泳社, 2009

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment