「テストを書いているのに、なぜかバグが見つからない…」そんな経験、ありませんよね?実はコンフォーマンステスト(仕様準拠テスト)だけでは見つけられないバグが存在するんです。
今、海外の開発者コミュニティで話題になっているのが、差分テスト(Differential Testing)を使ってTOONフォーマットの実装バグを初回実行で2つ発見した、というエピソードです。🎯
差分テストってなに?

イメージとしては「複数の採点者に同じ問題を解かせて、答えが違ったら誰かが間違っている」という方法です。
つまり、同じ仕様を実装した複数のプログラムに同じ入力を与えて、出力を比較するテスト手法のこと。どちらかが間違っていれば「答えが違う」ことで検出できます。
通常のコンフォーマンステストとの違いをまとめるとこんな感じです。
- ✅ 通常テスト:「正しい出力」を事前に人間が定義 → 定義漏れがあるとバグを見逃す
- ✅ 差分テスト:複数実装の「出力の一致」を確認 → 人間が気づかないコーナーケースも拾える
TOONってどんなフォーマット?
TOONは比較的新しいデータフォーマットで、TypeScript版のリファレンス実装とPython版のポートが存在します。今回の差分テスターは、この2つの実装を比較対象として動かしました。
実際にどんなバグが見つかったの?
初回実行でいきなり見つかったのが「サイレントコラプション(silent corruption)」バグ、2件。これが厄介なんですよね。
サイレントコラプションとは、エラーも警告も出さずにデータが静かに壊れるバグのことです。気づかずに使い続けてしまうので、通常のテストではなかなか検出できません。
差分テストの比較オラクルを自作してみよう
差分テストで一番難しいのが「比較オラクル(Comparison Oracle)」の設計です。イメージは「どちらの答えが正しいかを判断する審判」のこと。ざっくりとした流れがつかめるはずです👇
# 差分テストの基本的な考え方(Pythonサンプル)
import subprocess
import json
def run_impl(impl_command: list, input_data: str) -> str:
"""各実装を実行して出力を返す"""
result = subprocess.run(
impl_command,
input=input_data,
capture_output=True,
text=True
)
return result.stdout
def differential_test(test_cases: list):
"""2つの実装の出力を比較する差分テスト"""
for case in test_cases:
# TypeScript版とPython版にそれぞれ同じ入力を渡す
output_ts = run_impl(["node", "toon_ts.js"], case)
output_py = run_impl(["python", "toon_py.py"], case)
# 出力が一致しなければバグの可能性!
if output_ts != output_py:
print(f"[差分検出🚨] 入力: {case}")
print(f" TypeScript出力: {output_ts}")
print(f" Python出力 : {output_py}")
else:
print(f"[一致✅] 入力: {case}")
# テストケースをランダムに生成して差分テストを実行
test_cases = ['{"key": "value"}', '{"num": 42}', '{"nested": {"a": null}}']
differential_test(test_cases)
ここが重要です。ポイントをまとめるとこんな感じです。
- 🔑 同じ入力を複数の実装に渡すのが基本
- 🔑 出力の比較で「どちらかが間違っている」を検出できる
- 🔑 ランダムなテストケース生成(ファジング)と組み合わせると特に強力
まとめ
差分テストは「仕様書テスト」では見逃しがちなサイレントバグを炙り出す、とても強力なアプローチです。今回のTOON事例は、その威力を初回実行で証明してしまった好例ですよね。
自分が使っているライブラリや実装に複数バージョン・複数言語のポートが存在するなら、ぜひ差分テストを試してみてください。思わぬバグが見つかるかもしれません!🚀





