Python応用

速報!差分テストツール「TOON」の2つのサイレントバグを初回実行で発見した話

「テストを書いているのに、なぜかバグが見つからない…」そんな経験、ありませんよね?実はコンフォーマンステスト(仕様準拠テスト)だけでは見つけられないバグが存在するんです。

今、海外の開発者コミュニティで話題になっているのが、差分テスト(Differential Testing)を使ってTOONフォーマットの実装バグを初回実行で2つ発見した、というエピソードです。🎯

差分テストってなに?

software testing bug
software testing bug / Photo by Daniil Komov via Pexels

イメージとしては「複数の採点者に同じ問題を解かせて、答えが違ったら誰かが間違っている」という方法です。

つまり、同じ仕様を実装した複数のプログラムに同じ入力を与えて、出力を比較するテスト手法のこと。どちらかが間違っていれば「答えが違う」ことで検出できます。

通常のコンフォーマンステストとの違いをまとめるとこんな感じです。

  • ✅ 通常テスト:「正しい出力」を事前に人間が定義 → 定義漏れがあるとバグを見逃す
  • ✅ 差分テスト:複数実装の「出力の一致」を確認 → 人間が気づかないコーナーケースも拾える

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事例は、その威力を初回実行で証明してしまった好例ですよね。

自分が使っているライブラリや実装に複数バージョン・複数言語のポートが存在するなら、ぜひ差分テストを試してみてください。思わぬバグが見つかるかもしれません!🚀

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る

Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

もしも

Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

FastAPIでWebAPI開発を実践的に学ぶ

Amazonで見る

ESP32&Arduino 電子工作 プログラミング入門

もしも

ESP32&Arduino 電子工作 プログラミング入門

ESP32とArduinoで電子工作を学ぶ入門書

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です