テストコードはどれくらい書けば良いのか

テスト

はじめに

「テストコードってどれくらい書けばいいんだろう?」これは、多くの開発者が一度は抱く疑問です。100%のカバレッジを目指すべきなのか、それとも重要な部分だけで十分なのか。本記事では実践的な観点から適切なテストコードの量について見ていきます。

テストカバレッジの誤解

カバレッジ100%は目標ではない

多くの開発者が「カバレッジ100%」を目指してしまいますが、これは必ずしも正しい目標ではありません。カバレッジは「コードの何%が実行されたか」を示す指標であり、「テストの品質」を保証するものではないからです。

適切なテストコードの量を決める基準

1. ビジネスクリティカルな部分を重点的にテストする

すべてのコードが同じ重要度を持つわけではありません。以下のような部分は特に重点的にテストすべきだと考えます。

  • 決済・課金処理: バグが直接的な金銭的損失につながる
  • 認証・認可ロジック: セキュリティに直結する
  • データの整合性を保つロジック: データ破損は致命的
  • 複雑なビジネスロジック: バグの混入リスクが高い
# 決済処理は必ず十分なテストを書く
class PaymentProcessor:
    def process_payment(self, amount, card_info):
        # この関数は複数のテストケースでカバーすべき
        pass

# テスト例
def test_payment_with_valid_card():
    # 正常系
    pass

def test_payment_with_expired_card():
    # 異常系: 有効期限切れ
    pass

def test_payment_with_insufficient_funds():
    # 異常系: 残高不足
    pass

def test_payment_with_network_error():
    # 異常系: ネットワークエラー
    pass

2. 変更頻度が高い部分は手厚くテストする

頻繁に変更される部分は、バグが混入しやすい領域です。リファクタリングや機能追加の際に、既存の動作が壊れていないことを確認できるテストがあると安心になります。

実践的なテスト戦略

テストピラミッドを意識する

効率的なテスト戦略として「テストピラミッド」という考え方があります

        /\
       /  \    E2Eテスト(少量)
      /----\
     /      \  統合テスト(中量)
    /--------\
   /          \ 単体テスト(大量)
  /------------\
  • 単体テスト(70%): 高速で安定、多数書く
  • 統合テスト(20%): モジュール間の連携をテスト
  • E2Eテスト(10%): 重要なユーザーフローのみ

テストコードの品質を保つ

テストコード自体も保守対象

テストコードが多すぎると、以下の問題が発生します

  • コード変更時にテストの修正に時間がかかる
  • テストの実行時間が長くなり、開発速度が低下
  • 誤ったテストがあっても気づきにくい

良いテストコードの特徴

独立性: テストは互いに独立して実行できる

# 悪い例: 他のテストの結果に依存
test "create user" do
  @user = User.create(name: "Alice")
end

test "update user" do
  @user.update(name: "Bob") # 前のテストに依存
end

# 良い例: 各テストで準備する
test "update user" do
  user = User.create(name: "Alice")
  user.update(name: "Bob")
  assert_equal "Bob", user.name
end

可読性: テストコードは仕様書の役割も果たす

# 良い例: 何をテストしているか明確
def test_user_cannot_purchase_without_sufficient_balance
  user = User.new(balance: 100)
  product = Product.new(price: 150)
  
  result = user.purchase(product)
  
  assert_equal false, result.success
  assert_equal "Insufficient balance", result.error
  assert_equal 100, user.balance  # 残高は変わらない
end

高速性: 単体テストは数ミリ秒で完了すべき

チーム開発でのテスト戦略

最低限のルールを決める

チームで以下のようなルールを決めておくと良いと思います。

  1. 新機能には必ずテストを書く: テストがないPRは承認しない
  2. バグ修正時は再現テストを書く: 同じバグの再発を防ぐ
  3. CI/CDでのテスト実行を必須化: すべてのテストがパスしなければマージ不可

コードレビューでのチェックポイント

  • テストケースが不足していないか
  • テストが何を検証しているか明確か
  • テストが脆くないか(実装の詳細に依存しすぎていないか)

テストコードの品質を保つ

テストコード自体も保守対象

テストコードが多すぎると、以下の問題が発生します:

  • コード変更時にテストの修正に時間がかかる
  • テストの実行時間が長くなり、開発速度が低下
  • 誤ったテストがあっても気づきにくい

良いテストコードの特徴

独立性: テストは互いに独立して実行できる

# 悪い例: 他のテストの結果に依存
test "create user" do
  @user = User.create(name: "Alice")
end

test "update user" do
  @user.update(name: "Bob") # 前のテストに依存
end

# 良い例: 各テストで準備する
test "update user" do
  user = User.create(name: "Alice")
  user.update(name: "Bob")
  assert_equal "Bob", user.name
end

可読性: テストコードは仕様書の役割も果たす

ruby

# 良い例: 何をテストしているか明確
def test_user_cannot_purchase_without_sufficient_balance
  user = User.new(balance: 100)
  product = Product.new(price: 150)
  
  result = user.purchase(product)
  
  assert_equal false, result.success
  assert_equal "Insufficient balance", result.error
  assert_equal 100, user.balance  # 残高は変わらない
end

高速性: 単体テストは数ミリ秒で完了すべき

チーム開発でのテスト戦略

最低限のルールを決める

チームで以下のようなルールを決めておくと良いでしょう:

  1. 新機能には必ずテストを書く: テストがないPRは承認しない
  2. バグ修正時は再現テストを書く: 同じバグの再発を防ぐ
  3. カバレッジの基準を設定: 例: PRでカバレッジが5%以上下がらないこと
  4. CI/CDでのテスト実行を必須化: すべてのテストがパスしなければマージ不可

コードレビューでのチェックポイント

  • テストケースが不足していないか
  • テストが何を検証しているか明確か
  • テストが脆くないか(実装の詳細に依存しすぎていないか)

まとめ

テストコードの量に絶対的な正解はありません。重要なのは以下のポイントです。

  • ビジネス価値とリスクに基づいて優先順位をつける: すべてを均等にテストする必要はない
  • カバレッジは手段であり目的ではない: 数値だけを追い求めない
  • テストコードも保守コスト: 書きすぎも問題になり得る

最適なテスト量は、プロジェクトの成長と共に変化します。定期的に振り返り、チームにとって最適なバランスを見つけていきましょう。

コメント

タイトルとURLをコピーしました