Unity Test RunnerでSaveが書き換わる原因と対策

確認環境

Unity
6000.3.8f1
対象
Unity Editor / Play Modeテスト
検証OS
macOS 26.5.2 / Apple silicon Mac
関連Package
Unity Test Framework 1.6.4

結論

Unity Test RunnerのPlay Modeテストでは、テストコードが直接Saveを書いていなくても、Play Mode終了時の通常保存処理が実Saveへ到達する場合があります。

今回の原因は、direct -runTestsが独自のSave隔離処理を通らず、テスト終了後のOnApplicationQuitから実Saveへ書き込んでいたことでした。

対策は、すべてのテスト実行経路でSaveをテスト専用の保存先へ切り替え、Play Mode終了後まで隔離を維持することです。

症状

今回確認した症状は次のとおりです。

  • Play Modeテストはすべて成功していた
  • ゲーム状態そのものは変わっていなかった
  • テスト終了後、実JSON Saveのtimestampだけが更新されていた
  • Saveファイルのbyte hashがテスト前後で変化していた
  • Consoleには原因を示す例外が出ていなかった

原因

direct -runTestsが独自のSave隔離処理を通っていなかった

独自wrapperからテストを実行した場合は、実Saveではなく一時的なSaveへ切り替えていました。

一方、Unityをコマンドラインから直接-runTestsで起動すると、そのwrapperを通りませんでした。

そのため、テスト終了後に通常のSaveサービスへ戻り、次の保存処理が実Saveへ到達していました。

OnApplicationQuit -> SaveNowAsync -> SaveAsync

TearDown後にも保存処理が続いていた

Play Modeテストでは、テスト本体やTearDownが終わった後も、Play Mode終了やEditor終了に伴う処理が続きます。

TearDown直後にSave隔離を解除すると、その後のOnApplicationQuitが実Saveへ書き込む可能性があります。

確認方法

まず、テスト前後で実Saveファイルを比較します。

  1. テスト前にSaveファイルをコピーする
  2. byte hashを記録する
  3. Play Modeテストを実行する
  4. テスト終了後に再度hashを計算する
  5. hashが違う場合はJSON差分を確認する

ゲーム状態に差がなくても、timestampや最終保存時刻だけが変わっていないか確認してください。

次に、Play Mode終了時の保存経路を調べます。

OnApplicationQuit
Save
SaveAsync
SaveNow

独自のテストwrapperやSave overrideを使用している場合は、direct -runTestsでも同じ隔離処理が有効か確認します。

解決方法

Saveをテスト専用の保存先へ切り替える

Play Modeテスト中は実Saveを使用せず、次のいずれかへ切り替えます。

  • メモリ上のSave実装
  • テスト専用ディレクトリ
  • テスト専用Saveサービス

ゲームコード側で保存先やSaveサービスを差し替えられるようにすると、実Saveへ触れずにテストできます。

direct -runTestsも隔離対象にする

独自wrapperだけを開始条件にせず、Unity Test Runnerの実行開始を検知してSave隔離を開始します。

今回の対策では、direct -runTestsを含む実行中の内部Save書き込みを止め、テスト専用Saveへ切り替えました。

Play Mode終了後まで隔離を維持する

TearDownやRunFinishedで直ちに実Saveへ戻さず、Play Mode終了とTest Runnerの処理停止を確認してから隔離を解除します。

Editorが途中終了する可能性がある場合は、開始前のSaveを保持し、次回起動時に復元できるようにします。

関連記事

PlayerPrefsが消える問題については、Unity Test RunnerでPlayerPrefsが消える原因|DeleteAllに注意で説明しています。

参考資料