0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【単体テストの使い方/考え方】1.1 なぜ、単体テストを行うのか?

Last updated at Posted at 2025-09-14

なぜ、単体テストを行うのか?(単体テストの目的)

【結論】プロジェクトの成長を持続可能にするため
(ビジネスサイド側から見ると、顧客からの要求に速やかに対応できる)

  • プロジェクトが成長するとコードが複雑化するので、開発スピードは遅くなっていく
    • テストがない場合
      1. 「コードを変更・追加する→コード内の無秩序が増加する(=複雑化する)→コードを変更・追加する→ ‥‥」というループができる
      2. コードが複雑化していく
      3. 他の部分が機能しなくなる
      4. コードの信頼性が失われる
      5. 最悪の場合、安定した状態に戻せなくなる
    • テストがある場合
      • コードを変更しても、既存の機能が正しく動作することを保証してくれる
        →テストが退行を防ぐセーフティネットになる

単体テストの目的を達成するためにどうすればいいのか?

(再掲)単体テストの目的:プロジェクトの成長を持続可能にするため

【結論】

  • 網羅率を特定の数値以上にすることを義務付けない
  • 「単体テストの価値>保守コスト」となるようなテストケースだけを集める

網羅率を特定の数値以上にすることを義務付けない

  • 網羅率はテストの質が悪いこと(テストされていないコードが残っていること)を示せても、テストの質が良いことを証明できない

コード網羅率とは

  • コード網羅率とは「何行のプロダクションコードをテストできたか?」を測るもの

コード網羅率の欠点

1. コードをコンパクトに書けば網羅率が高くなるが、テストの価値は変わらない


テスト対象:messageが5文字以上かどうかをチェックする関数
テストケース:messageabc(3文字)の場合、falseを返却する

パターン1とパターン2は、テスト対象に期待する動作もテストケースも同じ
しかし、パターン2は三項演算子を使うことによって、パターン1よりもコード網羅率が高くなる

パターン1
# コード網羅率:3/4 = 0.75 = 75%
def isMessageLong(message):
    if len(message)>= 5:
        return true
    else:
        return false
パターン2
# コード網羅率:1/1 = 1 = 100%
def isMessageLong(message):
    return true if message <= 5 else false

分岐網羅率とは

  • 分岐網羅率とは、「何個の分岐経路をテストできたか?」を測るもの

分岐網羅率の欠点

1. 網羅率からは実際にテスト対象のコードが検証されたかを保証できない


テスト対象:引数messageが5文字以上かどうかをチェックし、その結果をグローバル変数wasLastStringLongに格納する関数
テストケース:messageabc(3文字)の場合、falseを返却する

→このテストケースでは、wasStringLongfalseということを保証できていない

# コード網羅率:1/1 = 1 = 100%
# 分岐網羅率:1/2 = 0.5 = 50%
def IsMessageLong(message):
    result = true if message <= 5 else false
    wasLastStringLong = result
    return result
2. 網羅率のを算出する際に、使用するライブラリ内のコードは検測の対象から外れる


テスト対象:引数inputint型に変換する関数
テストケース:inputstring型の"5"の場合、int型の5が返却される

変換にPythonの組み込み関数int()を使用して1行で書いているので、コード網羅率・分岐網羅率は100%になる
→しかし、Pythonの組み込み関数int()の中身が網羅率の検測対象から外れている
(整数ではない文字列、nullなど)

# コード網羅率:1/1 = 1 = 100%
# 分岐網羅率:1/1 = 1 = 100%
def parseInt(input):
    return int(input)

「単体テストの価値>保守コスト」となるようなテストケースだけを集める

コード(テストコードも含まれる)は資産ではなく負債
コードが増える=ソフトウェアにバグが持ち込まれる経路が増える

→そのため、むやみにテストケースを増やしてはいけない

  • 保守コストに含まれる例
    • プロダクションコードをリファクタリングした際に、テストコードもリファクタリングすること
    • プロダクションコードを変更するたびに、テストを実施すること
    • テストが間違って失敗した際にその対処をすること
    • プロダクションコードの振る舞いを理解するために、テストコードを読むこと

どのようにテストの質を評価するのか?

  • 各テストケースを1つずつ評価する
  • 自動的に評価できるような方法は存在しない

→それでは、どのようにテストの質を良くするのか?

テストの質を良くするポイント

  • テストすることが開発サイクルの中に組み込まれていること
  • コードベースの特に重要な部分のみがテスト対象になっていること
  • 最小限の保守コストで最大限の価値を生み出すようになっていること

テストすることが開発サイクルの中に組み込まれていること

コードベースの特に重要な部分のみがテスト対象になっていること

全てのコードベースが単体テストをする価値を持っているわけではない
→単体テストにかける労力をシステムにとって重要な部分に向ける

システムにとって重要な部分とは

システムにとって重要な部分とは「ビジネスロジックを含む部分=ドメイン・モデル

単体テストにかける労力をドメイン・モデルのみに集中させるためには、
ドメイン・モデルをコードベースの本質でない部分から隔離しておく必要がある

ドメイン・モデルではないコードとは?

  • インフラに関するコード
  • 外部サービスや依存関係のあるもの(データベースやサードパーティのシステムなど)
  • 構成要素同士を結びつけるコード

最小限の保守コストで最大限の価値を生み出すようになっていること

どうすれば最小限の保守コストで最大限の価値を生み出せるのか?

  • 価値のあるテストケースを認識できること(価値の低いテストケースも認識できること)
  • 価値のあるテストケースを作成できること

この2つは似ているようで異なる

価値のあるテストケースを認識できること(価値の低いテストケースも認識できること)

価値のあるテストケースを認識するためには...

  • テストケースの価値を評価するための基準となる枠組みを知っていること

価値のあるテストケースを作成できること

価値のあるテストケースを作成するためには...

  • テストケースの価値を評価するための基準となる枠組みを知っていること
  • 設計のテクニックについて理解していること
    • 単体テストとはテスト対象となるコードの内容を検証するものなので、コードベースが熟考された設計のもとで構築されていなければ、価値あるテストケースを作成できない
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?