Skip to content

TestStrategy

github-actions[bot] edited this page Sep 9, 2026 · 1 revision

Home

テスト戦略

このドキュメントは、FloatSoda のテストを「範囲 × 目的 × オラクル」の3軸で整理し、現在の配置と既知の穴をまとめたものです。テストの命名と「何を検証するか」の観点は CONTRIBUTING.md が正典で、このページはそれを置き換えません。テストをどこに置くかを決めるときの地図として使います。

1. 3つの軸

テストの種類は1本の軸には並びません。次の3軸を分けて考えます。

意味
範囲 単体 / 結合 / 描画 / 実機 どこまで結合して動かすか
目的 機能 / 回帰 / 非機能 / 受け入れ 何を確かめるか
オラクル 例示 / 不変条件 / ゴールデン / 差分 期待値をどう言うか

範囲の4値は FloatSoda の構造に対応します。

範囲 対象 実行手段
単体 ジオメトリ型、RenderObject 1個、Widget 1個 dotnet test
結合 WidgetBinding から RenderPipeline までを通した経路。差分更新、入力の配送 dotnet test
描画 FloatSoda.Testing のビットマップ描画で画素を確認する dotnet test
実機 SteamVR が動いている状態でしか観測できないもの。オーバーレイハンドル、コントローラーの座標、レンダースレッドの GL コンテキスト HMD を着けて手で操作する(.agents/skills/floatsoda-device-test)

オラクルは「期待値をどう言えるか」で選びます。

オラクル 期待値の言い方 向いている対象
例示 入力に対する正確な出力を書く サイズ計算、イベントの順序、画素の色
不変条件 常に成り立つ性質を書く ツリーの親子関係と深さ、dirty list の整合
ゴールデン 保存しておいた出力と一致する 描画結果の意図しない変化
差分 Flutter の挙動を正解として比較する Flutter 由来の Widget / RenderObject

差分オラクルは FloatSoda 固有です。Flutter を正解として使えるのは observable behavior だけで、性能や並行性には使えません。判断原則は APIDesign の「Flutter 由来の observable behavior に差異を作らない」にあります。

2. 組み合わせを切る基準

3軸を掛けると64マスになりますが、ほとんどは空でよい場所です。次の3つの基準で切ります。

  1. 最小範囲: 同じ壊れ方をより小さい範囲で観測できるなら、大きい範囲のマスは使いません。実機は「実機でしか見えないもの」だけに使います。
  2. オラクル成立: その範囲で期待値を言えないマスは使いません。非機能 × 差分は、Flutter の性能が .NET の正解にならないので全て空です。
  3. シナリオ: 「誰が・いつ・何をしたくなるか」を1文で言えないマスは使いません。負荷、セキュリティ、アクセシビリティ(Semantics は非移植の方針)は、この基準で外れます。

この表は穴を見つけるために使います。「ある」が付いていないマスを機械的に埋める必要はありません。

3. 現在の配置(2026-09-09 時点)

64マスのうち、基準を通過したのは14マスです。件数は [Fact][Theory] の数です。

目的 範囲 オラクル 現状 根拠
機能 単体 例示 ある tests/FloatSoda.Test 412件、tests/FloatSoda.Rendering.Test 8件
機能 単体 不変条件 薄い [Theory] 47件はあるが、ツリー不変条件を機械的に検査するヘルパーは無い
機能 単体 差分 手順のみ CONTRIBUTING が Flutter 公式テストの参照を必須にしている。テスト自体は例示として書かれる
機能 結合 例示 薄い WidgetBinding を端から端まで動かすのは Core/WidgetBindingTest.csCore/PointerInputIntegrationTest.cs の2ファイル
機能 描画 例示 ある GetPixel による画素の断言が15ファイル、84箇所
機能 実機 例示 無い device test の手順はあるが、ハーネスは未着手
機能 実機 差分 文書のみ known-divergences.md に9件。うち8件が Test: — (not set)
回帰 単体 例示 ある バグ修正ごとの regression test を REVIEW.md が必須にしている
回帰 描画 ゴールデン 無い 参照画像はゼロ。GetPixel で足りている間は優先度が低い
非機能 結合 例示(閾値) 未着手 tests/FloatSoda.Test/FloatSoda.Test.csproj が BenchmarkDotNet を参照しているが、[Benchmark] はゼロ
非機能 結合 不変条件(並行性) 薄い スレッドを扱うのは Engine/IOTaskRunnerTest.cs など数件。レンダースレッドと Layer clone の競合は未検証
受け入れ 実機 例示 手動 samples/ は CONTRIBUTING で「結合テストのシナリオを兼ねる」とされるが、CI はビルドのみ。実行には SteamVR が要る
受け入れ 文書と API 例示 手動 junior-coder test(.agents/skills/floatsoda-junior-coder-test)。実績あり。LLM を使うので CI には乗せない
受け入れ 文書 例示(スモーク) ある website/scripts/verify-dist.mjs

4. 既知の穴と優先順位

影響が大きい順です。

  1. Flutter との差異がテストで固定されていない。 差異は意図した仕様なので、テストで固定しないと次の移植作業で気づかずに元へ戻ります。9件のうち半分は実機を使わず、単体か結合で固定できます。振り分けは §5 を参照してください。
  2. 結合が2ファイルしかない。 差分更新の dirty 伝播と入力の配送経路は、単体では見えず、実機では遅すぎます。この中間の範囲を厚くします。
  3. BenchmarkDotNet が宙に浮いている。 依存だけあってベンチマークがありません。「1フレームの予算内にレイアウトが収まるか」は Booth 創作者のペルソナが最も気にする点なので、書くか外すかを決めます。

優先度が低い、または判断待ちの項目です。

  • ツリー不変条件のヘルパー: ツリー操作の後に親子関係と深さを検査する共通ヘルパー。安価に足せます。
  • ゴールデン: SkiaSharp の更新で描画が変わる事故を捕まえる用途に限ります。GetPixel で捕まえられない事故が起きるまで保留します。
  • samples/ の位置づけ: 規約上は結合テストのシナリオですが、実行手段は実機だけです。実機シナリオとして扱うか、ヘッドレスで実行する仕組みを作るかは未決定です。
  • ペルソナ2・3の受け入れ: Unity 出身者が uGUI の語彙で読めるかを確かめる手段がまだありません。シナリオは書けますが実行手段が無いので、名前だけ残します。

5. Flutter との差異とテストの関係

差異の台帳は known-divergences.md です。テストを書く前にラベルを決めます。 ラベルによって、書くべきテストの向きが逆になるためです。

ラベル 書くテスト
deliberate 差異を固定するテスト。差異を元に戻すと落ちる
port mistake 修正前に落ち、修正後に通る regression test
not ported テストは書かず、Issue を立てる
unlabelled 先にラベルを決める。この状態でテストを書くと、バグを仕様として固定する恐れがある

9件それぞれの範囲、テスト名、着手順は、台帳末尾の「Triage 2026-09-09」節に記録しています。

6. 片付けの計画

Phase 2 のリリース(Home)後に着手します。順番は次のとおりです。

  1. 差異の固定テスト。台帳の Triage 節の順(#4 → #5 → #1 → #7)
  2. 結合テストの拡充。dirty 伝播と入力の配送
  3. BenchmarkDotNet を書くか外すかの判断
  4. 台帳の更新。#5 の Flutter 欄の書き直し、#2 と #3 の統合、#6 の分割

着手したら §3 の表と §4 の一覧を更新し、日付を書き換えます。

Clone this wiki locally