シリーズ: AI とともにコードを学ぶ

54%から100%のテスト合格へ

三週末で54パーセントから100パーセントのテスト合格へと歩んだ道のり。

54%から100%グリーンへ 三週末、四つの根本原因修正、一つの誠実な数字 54% 63% 63% 100% 土曜午前 土曜午後 第2週 第3週
ごまかせない唯一の数字:56件中56件のテストが合格。

パートナーが空間ランタイムを評価するとき、最初に尋ねるべき数字は統合テストの合格率だ。ここに、私たちのそれを辛うじて動く状態から万全な状態へと引き上げた経緯と、スナップショットよりも軌跡が重要である理由を記す。

コードベースについて嘘をつかない数字はテスト合格率だ。売上の数字はごまかせる。スター数は水増しできる。コード行数は肥大化させられる。テスト合格率はテストランナーが言う通りのものであり、テストランナーはあなたの感情を気にしない。

一週間前の土曜日にラップトップを開いたとき、数字は54%だった。五十二件中二十八件のテスト。壊滅的ではない。グリーンでもない。コードベースが概ね動いているが、どこが動いていないか正確には分からない、という類の数字だ。その土曜の夜には、数字は63%(33/52)になっていた。今終わったばかりの日曜には、100%(56/56)になっていた。この投稿は、その数字の間にある道のりについてのものだ。

なぜ最初は数字が低かったのか

いくつかの重なり合う理由がある。

失敗すべきテストにスタブが合格していた。 数週おきに現れるテーマだ。スイート内のいくつかのテストは戻り値をゼロと比較しており、たまたまスタブ実装がゼロを返し、そのテストがそれを成功と呼んでいた。ハーネスは嘘をついていなかった。テストが同語反復だった。

いくつかのアサーションが実際のエラーコードと食い違っていた。 あるテストは、不正な入力に対してfont_set_data-1を返すことをアサートしていた。実際の実装は-3を返していた(これはRAKU_ERROR_INVALID_PARAMETERにマッピングされる、テストが書かれた対象よりも具体的なコードだ)。どちらの挙動も有効だ。テストはエラーコードが統一される前に書かれていた。修正はテストを更新して任意の負のエラーコードを受け入れるようにすることであり、実装を変えることではなかった。

テレメトリのテストには追跡すべき状態がなかった。 あるクラスのテストは、「イベントXを発火した後、テレメトリシステムはそれを記憶しているはずだ」とアサートすることでテレメトリ・イベントパイプラインを運動させていた。当時のテレメトリ・サブシステムは何も記憶しないスタブのイベントトラッカーを持っていた。テストが失敗していたのは、パイプラインが壊れていたからではなく、まだパイプラインが存在しなかったからだ。

視線追跡モジュールの戻り値の慣例が逆転していた。 一部の視線追跡C API関数は、Win32寄りの開発日に書かれたため成功時に1を返していた。エンジンの残りの部分は成功時に0を返す。エンジンの残りの部分に対して書かれたテストは、悪いコードではなく慣例のドリフトのために、視線追跡モジュールで失敗していた。

MSVCビルドには不透明ハンドルのキャストにハードなコンパイルエラーがあった。 XrInstanceはOpenXRの不透明ハンドル型だ。シリアライズのためにそれをuint64_tにキャストするには、static_castではなくreinterpret_castが必要だった。MSVCはC2440で大声のエラーを出していた。修正は一行の変更だった。それが隠していたテスト失敗はもっと大きかった。

作業はどのようなものだったか

具体的に書き留めておきたい。なぜならテスト修正のパターンは再現可能だからだ。

土曜午前(29/52 → 31/52): 一部のテストがコンパイルすらできなくしていたビルドエラーを解消。reinterpret_castの修正で二件のテストが即座にブロック解除され、コンパイル失敗の裏に隠れていた三件目が浮上した。

土曜正午前後(31/52 → 33/52): テレメトリのスタブを、状態を持つイベント追跡実装に置き換える。スタブは何もしない二行の関数だった。実際の実装はスレッドセーフなベクターでイベントを追跡し、クエリAPIを公開し、ハーネス内の三つのテレメトリテストに対して正しい挙動を生み出す。telemetry_stubs.cppは、本番のテレメトリサブシステムを十分に忠実に模倣し、テストが実際の理由で合格するようなテストダブルとして書いた。

土曜午後(33/52 → 33/52、件数は増えなかったが質のジャンプ): test_edge_cases内の間違ったエラーコードをチェックしていたアサーションを修正。修正は、アサーションが書かれていた特定の-1ではなく、任意の負のエラーコードを受け入れるようにすることだった。テストは今、実際の実装の実際のエラーパスを運動させる。

一週間後(33/52 → 33/52 → 53/52 → 56/56): 視線追跡の慣例ドリフトが最も時間を要した。視線追跡のC APIは、エンジンの残りの部分とは異なる戻り値の慣例を持っていた。慣例を揃えるには、実装(成功時に0を返す)と呼び出し側(0を期待する)の両方を更新する必要があった。揃えた瞬間、二十件のテストが一度にグリーンになった。カスケード効果は本物だ。

その後の週末はtest_memory_leaksの週末だった。九件のテストが、リーク検出ハーネスの下でのみ表面化するメモリ関連の理由で失敗していた。修正は一行に収まらない類の慎重な作業だった:InputQueueは実際のadd/get/predict/trimの挙動が必要な何もしないスタブだった。RollbackSession::initializeはコールバックを受け入れる前に検証する必要があった。NetworkQualityEstimatorはsend/ackペアからRTTとパケットロスを実際に追跡する必要があった。そしてECS World::clearは、次回の割り当てサイクルで古いインデックスが再利用されるのを防ぐため、空きインデックスキューを排出する必要があった。

最後のもの(ECSの空きインデックスキュー)は、クラッシュを生まないが後に極めて微妙なバグを生む種類のものだ。空きインデックスキューは、エンティティ・コンポーネント・システムがエンティティ破棄後にハンドルを再利用する仕組みだ。clearがキュー内に古いインデックスを残すと、次に作成されるエンティティは以前削除されたエンティティのものと重複するハンドルを得てしまい、削除されたエンティティへの参照が静かに新しいエンティティを指すようになる。診断は困難。混入は容易。メモリリークテストがこれを捕まえたのは、リーク検出器がどのハンドルが割り当てられたかを追跡していたからだ。

その週末が終わる頃には、テストスイートは56/56、100%になっていた。

何を学んだか

三つのことだ。

慣例のドリフトは測定するまで見えない。 視線追跡モジュールは単独では動いていた。成功時に1を返すのに対しエンジンの残りが0を返すという事実は、誰もそれに対してクロスモジュールのテストを書いていなかったため、誰も噛みついていなかった。モジュールをまたぐほど大きくなったテストスイートが、そのドリフトを二十通りの方法で一度に露呈させた。テストスイートは慣例が監査される仕組みだ。

テストに合格するスタブは、失敗するスタブより悪い。 どちらもスタブだ。どちらも最終的に本物の実装が必要だ。テストに失敗するスタブは、スタブであることに正直だ。たまたまテストに合格するスタブは、コードベースが自分自身についている嘘だ。嘘をつくスタブを表面化させる監査こそが、コードベースを最も改善する監査だ。

カスケード効果こそが報酬だ。 視線追跡の慣例修正は一度の押し込みで二十件のテストをブロック解除した。ECS World::clearのメモリリーク修正はさらに九件をブロック解除した。テスト合格率の大きな勝利は、二十個の個別のバグを修正することからは来なかった。それぞれ複数の下流のテスト失敗を持つ四つの根本原因を修正することから来た。

パートナーとビルダーがここから学ぶべきこと

パートナーシップのためにエンジンを評価していて、テスト合格率が90%を下回っているなら、軌跡について尋ねてほしい。54%から始めて三週末で100%になったチームは、六か月間80%に留まっているチームとは別のチームだ。

エージェント駆動のワークフローを実行していて、テスト合格率が望む水準にないなら、エージェントがもっと賢くなる必要があると決めつけないでほしい。テストを見てほしい。同語反復的なテスト、慣例のドリフト、たまたま合格するスタブ。修正は通常、実装ではなくテストハーネス側にある。

自律的なPRのためのコーディングエージェントを構築しているAIラボなら、私が最も予測力があると考える指標は「エージェントのPRが着地した後、テスト合格率は上がるか」だ。多くのエージェントは、そのコードに対して合格するコードとテストを出荷するPRを着地させるが、実際の製品のカバレッジには何の改善もない。統合テスト合格率を動かすエージェントは違うエージェントだ。最適化する価値がある。

一週間前の土曜日、数字は54だった。今夜は100だ。テストランナーは私の感情を気にしない。テストランナーはその点で正しい。

グリーンのスイートとともに日曜日にラップトップを閉じる。来週末また構築に戻る。

自らの品質を証明するランタイムの上に構築する

RakuAIは、あなたのアシスタントが現実世界に住まうAIネイティブな空間ランタイムだ。グリーンのテスト、誠実なシグナル、エンジン級の規律——あなたのチームがその上で何を作れるか見てほしい。

← すべての記事