やらなイカ?

たぶん、iOS/Androidアプリの開発・テスト関係。

Unity Test Framework learning materialsをやってみた

Unity Test Frameworkパッケージのバージョン1.3では、マニュアルの中にUnity Test Framework learning materialsというドキュメントが追加され、またそのサンプルコードがパッケージのSamplesに含まれるようになりました。

ドキュメントは、Unity Test Frameworkの基本的な使いかたを紹介するGeneral Introductionと、サンプルプロジェクトを題材にゲームの操作を伴うテストを書くTesting Lost Cryptで構成されています。

以下、それぞれ紹介します。

General Introduction

Unity Test Frameworkの基本的な使いかた(ユニットテスト中心)を紹介しています。

サンプルコードはUnity Test Framework v1.3.0のSamplesにあるのですが、恐らくパッケージの設定に不備がありPackage Managerウィンドウからインポートすることができません*1 *2。 サンプルコードを見たいのであれば、Unity Test Frameworkをv1.3.0にアップグレードし、 Library/PackageCache/com.unity.test-framework@1.3.0/Samples~/ にあるファイルを直接見るしかなさそうです。

サンプルは、例えば1_RunningTest_ProjectがExercise1のテスト対象のみ、模範解答的テストを書いたものが1_RunningTest_Project_Solutionにあるという形式です。 なお、Exercise間で同じ名前のアセンブリを定義しているため、そのままでは同時に1つのSampleしかインポートできません*3。 インポートしたらasmdefファイル内のアセンブリ名を変えていくとよいでしょう。

以下、各Exerciseの内容です。

  1. Running Tests: 最初のテストを書いて実行するもの。テスト対象にバグがあって修正するというものなので、テスト初心者の方は1_RunningTest_Projectから見ることをおすすめします
  2. Arrange, Act, Assert: 読みやすいテストの書きかたとして3Aを紹介*4
  3. Semantic Test Assertion: NUnit3の制約モデルでのアサーションの書きかた、Does.Contain().And.Contain()といった表現力を紹介
  4. Custom Comparison: Unity Test FrameworkのEqualityComparerで許容誤差ありの比較
  5. Asserting Logs: LogAssert.Expectによるログ出力の検証
  6. Set Up and Tear Down: テストメソッドの前後に処理を行なう方法*5
  7. PlayMode Tests: 再生モードでテスト実行する方法
  8. PlayMode Tests in Player: スタンドアロンプレイヤーでPlay Modeテストを実行する方法
  9. UnityTest Attribute: UnityTest属性による複数フレームにまたがるテストの例*6
  10. Long Running Tests: 実行に時間がかかるテストにCategory属性およびExplicit属性を指定して実行タイミングをコントロールする方法
  11. Scene Based Tests: Edit ModeテストでSceneファイルをロードしてScene内のGameObjectを検証する方法*7
  12. Build Setup and Cleanup: テストのビルド前後に処理をはさむ IPrebuildSetup および IPostBuildCleanupの使いかた。テスト対象のSceneがプロジェクトのScenes in Buildに無いときに追加している*8
  13. Domain Reload: Edit Modeテストでスクリプトコンパイルなどドメインリロードを挟むテストの書きかた*9
  14. Preserve Test State: ドメインリロードが発生するテストでは変数が失われるので、回避策としてSerializeField属性を使う例*10
  15. Test Cases: TestCase属性によるパラメタライズドテストの書きかた。本文ではTestCaseSource属性・Values属性・ValueSource属性にも触れられています
  16. Custom Attributes: NUnitのカスタム属性を定義する例*11
  17. Runnings Tests Programmatically: TestRunnerApiの使用例。Sceneのバリデーションをテストとして実装し、それをメニューから呼ぶサンプル

Exercise16を除けば拙書『Unity Test Framework完全攻略ガイド』でも解説している内容です。日本語でより詳しい解説がほしい方はぜひ購入を検討してください。

www.nowsprinting.com

Testing Lost Crypt

2Dゲームサンプル『Lost Crypt』を題材とした統合テスト(ユニットテストより結合度の高いテスト)の書きかたです。 こちらはSamplesにファイルはありません。

以下、内容と補足説明です。

Setting up

題材となるLost Cryptプロジェクト(無料)のセットアップを行います。

assetstore.unity.com

Running a test in LostCrypt

Sceneをロードして、GameObject "FX - Day"が存在することを確認するテストを追加します。

Moving character

テストコードからキャラクターを操作する仕組みを実装します(まだテストではない)。

Lost CryptはNew Input Systemパッケージ(UnityEngine.InputSystem名前空間)を使用していますが、New Input SystemのInputAction(抽象化層)は使用しておらず、低レベルAPIを使用して独自の抽象化層(CharacterController2Dクラス)を実装しています。 そのため、テストの実装方式は旧Input Managerでも近い形式で実装できるものになっています。

New Input SystemのInputActionを使用しているのであれば、New Input SystemパッケージのマニュアルにあるInput testingが参考になるでしょう*12

Reach wand test

キャラクター操作の延長で、Scene右端にあるワンドにたどり着くテスト。 たどり着くかはキャラクターの座標で判定、規定時間を過ぎたらタイムアウト*13で失敗するテストを書きます。

Collision test

コリジョン抜けのテスト。 実際にコリジョン抜けバグがあるのが草。

Asset change test

操作(ワンドまでたどり着く)によってアセットの変化(SpriteLibraryのnameが切り替わること)を検証するテスト。

Scene validation test

Scenes in Buildに指定されている各Sceneに対して、SaraとWandが存在することを検証するパラメタライズドテストの例。

Performance tests

Performance Testingパッケージを使用して、fpsを計測・検証する例。

まとめ

こういったコンテンツが公式から出てくることはとても良いですね!*14

これを機にUnityのテストについて詳しく知りたい! という方は、ぜひ拙著『Unity Test Framework完全攻略ガイド』を読んでみてください*15

www.nowsprinting.com

また、統合テストにはAutomated QAパッケージも有用です*16。こちらも拙著『Unity Automated QA攻略ガイド』を参考にしてください。

www.nowsprinting.com

*1:いくつかのUnityバージョンでダメでした。そうゆうとこやぞ…

*2:v1.3.2で修正されました。see: https://unity3d.atlassian.net/servicedesk/customer/portal/2/IN-23368

*3:ほんとそうゆうとこ…

*4:拙書『Unity Test Framework完全攻略ガイド』ではTeardownを加えた「4フェーズテスト」を紹介しています。ほぼ同じものです

*5:ファイル削除はTearDownでなくSetUpで行なうべきです。例として仕方ないところなのですが

*6:SamplesにはInitTestScene637147869846377210.unityというファイルが含まれているのですが、これはPlay Modeテスト実行時に自動生成されるSceneなので不要です

*7:これもTearDownでEditorSceneManager.NewSceneしているのはよくない。SetUpでやるべき

*8:拙書『Unity Test Framework完全攻略ガイド』ではITestPlayerBuildModifierで行なう方法を紹介しています

*9:SamplesのコードはパスのセパレータがWindowsのもの(\)になっています。ほかのOSの場合は修正要

*10:ドメインリロードでは(OneTimeSetUpやSetUpは再実行されるけど)UnitySetUpは再実行されないことが前提知識なのですが、書かれていない

*11:ただし例として書かれているものはMaxTime属性で実現できるものだし、使用しているIWrapTestMethodは非同期テストに使用できない属性なので、よい例とは思えない

*12:こちらもいくつかツッコミどころがあるのですが、それはまた稿を改めて

*13:Timeout属性に触れられていないのですがyield return nullではタムアウトが機能しなかったりテストがフリーズしたりします

*14:質はともかく、と言いたいところなのですが、品質関係のコンテンツの品質が低いのはちょっとよくないなと思うのです…

*15:Amazon Kindle版・ペーパーバック版も進めています。今しばらくお待ち下さい

*16:開発停止中ですが、Unity Test Framework v1.3で非同期テストも実装されたので、そろそろ開発再開されることを期待しています