テスト出力のノイズを除去する複数の改善

puma/puma

Pumaのテスト実行時に余分な出力が混入していた問題を解消するため、ビルドの静粛化・非推奨警告のキャプチャ・テストヘルパーのリファクタリングなど、複数の改善がまとめて適用されました。

背景

テストが成功している(グリーン)にもかかわらず、標準出力やエラー出力にノイズが混入していました。このPRのタイトル「No stuff in my green dots.」が示す通り、. だけが並ぶはずのクリーンなテスト出力が、警告メッセージやビルドログによって汚染されていたことが動機です。

出力ノイズの発生源は大きく3つありました。C拡張のビルド時に make が出力するログ、非推奨メソッドが呼ばれた際に $stderr へ直接書き出される警告、そしてURLマップのテストで有効化されていた log: true オプションです。

技術的な変更

複数のファイルにまたがる変更が、それぞれ独立したノイズ源を排除しています。

Rakefileのビルド出力の抑制では、task :test => [:compile] の直接依存を compile_for_test という中間タスクに切り替えました。このタスクは ENV["MAKEFLAGS"]-s(silent)フラグを追加してから :compile を呼び出し、ensure ブロックで元の値を確実に復元します。

task :compile_for_test do
  original_makeflags = ENV["MAKEFLAGS"]
  ENV["MAKEFLAGS"] = [original_makeflags, "-s"].compact.join(" ")
  Rake::Task[:compile].invoke
ensure
  ENV["MAKEFLAGS"] = original_makeflags
end

task :test => [:compile_for_test]

ensure により、compile が例外で失敗した場合でも MAKEFLAGS が汚染されたままにならないよう環境変数が保護されています。

test/test_config.rbの非推奨警告のキャプチャでは、on_bootedon_restarton_stopped の3つの非推奨エイリアスに関するテストが修正されました。これらのテストはこれまで警告メッセージを $stderr へ素通りさせていましたが、capture_io ブロックで囲むことで出力をキャプチャし、警告メッセージの内容を assert_match で検証するようになりました。

# 変更前: 警告がそのまま $stderr に流れていた
conf = Puma::Configuration.new do |c|
  c.on_booted { ran = true }
end
conf.clamp
conf.events.fire_after_booted!
assert ran, "on_booted callback should have run"

# 変更後: 警告をキャプチャして内容も検証する
err = capture_io do
  conf = Puma::Configuration.new do |c|
    c.on_booted { ran = true }
  end
  conf.clamp
  conf.events.fire_after_booted!
end.last
assert_match(/Use 'after_booted', 'on_booted' is deprecated and will be removed in v8/, err)
assert ran, "on_booted callback should have run"

この変更は出力を抑制するだけでなく、警告の内容が正しいかどうかも検証するという点で、テストの品質も向上させています。

test/test_request_single.rbのヘルパーリファクタリングでは、create_client メソッドに peer_addr: キーワード引数が追加されました。従来、カスタムの peeraddr を設定するには create_client のブロック内で @rd.define_singleton_method を直接呼び出す必要がありましたが、新しいインターフェースではメソッド引数として渡せるようになりました。

# 変更前
create_client("GET / HTTP/1.1\r\n\r\n") { |_client|
  @rd.define_singleton_method(:peeraddr, peer_addr)
}

# 変更後
create_client("GET / HTTP/1.1\r\n\r\n", peer_addr: peer_addr)

test/test_url_map.rbでは、cli_server の呼び出しから log: true オプションが単純に削除されています。

lib/puma/cluster/worker.rbでは、テスト出力とは別に、rescue IOErrorrescue SystemCallError, IOError に拡張されています。IOError は一部のシステムコール起因のエラーをカバーしないため、SystemCallErrorErrno::EPIPE などのスーパークラス)を追加することで、パイプ書き込み失敗などのケースでも適切に break できるようになっています。

設計判断

環境変数の汚染防止に ensure を使用した点は注目に値します。ENV["MAKEFLAGS"] = "-s" と上書きする最も単純な実装も考えられますが、既存の MAKEFLAGS が設定されている環境での動作や、ビルド失敗時の状態保全を考慮し、compact.join による既存値との結合と ensure による復元が採用されました。

非推奨警告の「抑制」ではなく「検証」への転換も重要な設計判断です。capture_io の戻り値から stderr を取り出して assert_match で検証することで、「警告が出ないこと」ではなく「正しい警告が出ること」を担保する方向に改善されています。非推奨警告のメッセージが将来変更された場合にテストが失敗するようになるため、リグレッションの検出能力が高まっています。

まとめ

このPRは、テスト出力のノイズ除去という実用的な目的のもと、ビルドの静粛化・テストアサーションの強化・ヘルパーのインターフェース改善・エラーハンドリングの堅牢化という4つの独立した改善を一度に実現しています。「グリーンなテストはクリーンに」という原則の徹底が、コード品質全体の底上げにつながっている変更です。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
87ad6656

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文(総論)→背景・技術詳細・設計判断(各論)→まとめ(結論)という「総論→各論→結論」の3部構成が明確で、非常に分かりやすい記事構成です。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックのファイル名指定は正しく使用されていますが、フッターのPRリンク記法がガイドラインの推奨形式(例: [#123](URL))とわずかに異なります([PR #3942](URL))。ただし、リンクとして機能しており、内容理解には影響しません。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Rakeタスク、テストヘルパー、環境変数の扱いなど、専門知識を持つエンジニアを対象とした適切な技術レベルと表現で書かれています。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論・各論の構造を持ち、各パラグラフがトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られており、可読性が高いです。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

Rakefile、テストファイル、ワーカーファイルなど、複数のファイルにまたがる変更の要点を、Diffの内容と一致する形で正確に引用・解説できています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

MAKEFLAGS, capture_io, SystemCallErrorなど、関連する技術用語が文脈に応じて正確かつ適切に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

ビルド出力の抑制、非推奨警告の検証、ヘルパーのリファクタリングなど、各変更の技術的な目的と実装方法に関する説明が論理的かつ正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

PR Descriptionが非常に短いにもかかわらず、Diff内のコード変更という事実に基づいて、背景や設計判断を的確に解説しており、ハルシネーションは見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#3942)や警告メッセージ内のバージョン番号(v8)など、記事に含まれる数値や固有名詞はすべて正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

PRの主題である「テスト出力のクリーンアップ」を、記事タイトル「テスト出力のノイズを除去する複数の改善」が的確に表現しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事内のすべての主張は、PRのDiff情報から直接的または間接的に裏付けられており、PRに記載のない外部知識の持ち込みはありません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

非推奨警告メッセージ内の「will be removed in v8」という未来の表現を正しく引用しており、時間表現の歪曲はありません。