やらなイカ?

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

Unity 2021.2未満でも動作するRoslyn Analyzerプロジェクト

Unity 2020.2から制限付きながらRoslynアナライザが動作するようになり、その後、Unity 2021.1.2で実用段階に行き着いたことは以前ブロク記事で紹介しました。

www.nowsprinting.com

しかし、この時点でUnityエディター上で動作しない*1アナライザがありました。例えば次のものです*2

これらは、Unity 2021.2.0以降では動作するようになりました。

結論

調査を放置していたのですが改めて確認してみたところ、結論としては

  • Unity 2021.2から内包するMicrosoft.CodeAnalysis.CSharpバージョンがv3.5からv3.9に変更された
  • Microsoft.CodeAnalysis.CSharpのバージョン3.6以降を使用してビルドされたアナライザはUnity 2021.2未満では動作せず、2021.2以降では動作する
  • Microsoft.CodeAnalysis.CSharpのバージョン3.10以降を使用してビルドされたアナライザはUnity 2021.2以降でも動作しない[11/14追記]

というものでした。 したがって、自作アナライザをUnity 2021.2未満にも対応させたいのであれば、使用するMicrosoft.CodeAnalysis.CSharpはv3.5に固定すればよいということになります*3

テンプレートプロジェクト

こちらのリポジトリで、Unity 2021.2未満でも動作するアナライザプロジェクトのテンプレートを公開しています。 テンプレート初期化の確認中にミスってリポジトリ消してしまったので、以前☆つけてくれていた方はまたお願いします…。

github.com

内包するRoslynバージョンの確認方法

以下おまけです。

Unityに内包されているRoslyn関連ファイルは、macOSでは下記パスにあります。

Unity 2021.2未満

/Applications/Unity/Hub/Editor/2021.1.28f1/Unity.app/Contents/Tools/Roslyn/Microsoft.CodeAnalysis.CSharp.dll

2021.1.28f1の部分はUnityエディタのバージョン

Unity 2021.2以降

/Applications/Unity/Hub/Editor/2021.3.4f1/Unity.app/Contents/Tools/ScriptUpdater/Microsoft.CodeAnalysis.CSharp.dll

この中のdllファイルを、Windowsであればilasm.exeというツールで見て確認できるはずです。 macOSの場合、Visual Studio for Macでも見られるようです。

参考:方法: ファイルがアセンブリであるかどうかを確認する | Microsoft Learn

今回はJetBrains Riderで読み込んで、Project Explorerでファイル右クリック | View in Assembly Explorerで確認しました。

*1:本稿での「動作しない」は、何ひとつコンソールに出力されずエラーメッセージも得られないもの

*2:全部検証しているわけではないので他にもあるでしょう。またバージョンによって振る舞いが異なる可能性もあります

*3:とはいえ、前述の通りUnity 2020 LTSのアナライザサポートには問題があるため、実質アナライザを活用していくのはUnity 2021 LTS以降ということで気にしなくてよさそうですが

Unity Automated QAのInput Systemサポートによる自動テスト

Unity Automated QAパッケージのRecorded Playback機能は、デフォルトではuGUI操作を記録・再生します。 しかし限定的ですが「Input Systemサポート」も提供されており、以下の操作に限り動作させることができ(ると書かれてい)ます。

  • UnityEngine.Input(従来のInput Manager)のみ*1
    • Supported Attributes: touches, touchCount, mousePosition
    • Supported Methods: GetTouch, GetMouseButton, GetMouseButtonDown, GetMouseButtonUp, GetKey, GetKeyDown, GetKeyUp, GetButton, GetButtonDown, GetButtonUp

Input Systemサポートについて、昨年末の同人誌『Unity Automated QA攻略ガイド』で調査途中と書いたままとなっていましたが、改めて調査してみました。 今さら感ありますが、そろそろホールドされているAutomated QAパッケージの開発が再開されるとされている時期なので期待も込めて。

www.nowsprinting.com

テスト対象の準備

Unity Asset Storeで無償提供されている2D Game Kit v1.9.5を使用しました。 選定理由は、New Input SystemおよびInput.GetAxis()*2を使っていないためです。

assetstore.unity.com

Unity 2022.1.20f1で開いたところ、UnityEngine.RuleTileがUnity.2D.Tilemap.Extras内にも定義されているというエラーが出たため、Assets/2DGamekit/Scripts/Utility/RuleTile.cs内のものをRuleTile2にリネームしています。

ここに、Automated QAパッケージをインストールします。 一覧には出てきませんが、 Package ManagerのAdd package by name...で"com.unity.automated-testing"を入力すればインストールできます。

記録のための設定

デフォルトではInput Managerによるキー入力は記録されません。 UnityエディタのメニューからAutomated QA | Automated QA Hub | Settingsを開き、Record Input Managerをonにします*3

再生のためのコード修正

続いて、キャラクター操作部分を少し書き換えます。 2D Game Kitでは、Inputから直接入力を取得しています。これにAutomated QAのPlaybackが介入できるよう、RecordableInputに置き換えます。

ファイルは、Assets/2DGamekit/Prefabs/EllenにアタッチされているAssets/2DGamekit/Scripts/Character/MonoBehaviours/InputComponent.csです。

次のような箇所を

Down = Input.GetButtonDown(k_ButtonsToName[(int)controllerButton]);

このように書き換えます*4

Down = RecordableInput.GetButtonDown(k_ButtonsToName[(int)controllerButton]);

Automated QAのアセンブリへの参照が必要です。 製品では、リリースビルドから除くため #if (UNITY_EDITOR || UNITY_INCLUDE_TESTS) を使うなどしたほうがいいでしょう*5

Automated QAパッケージにパッチを当てる

Input Managerの記録部分にバグがあり、パッチを当てる必要があります。 これは操作を記録する工程で必要なパッチであり、記録されたJSONファイルの再生時には無くても問題ありません。 言い換えると、再生だけならパッチを当てない素のパッケージを利用できます。

まず、パッチを当てるために、Automated QAパッケージを組み込みパッケージ化します。 プロジェクトディレクトリ下のLibrary/PackageCache/com.unity.automated-testing@0.8.1-preview.2を、Packagesディレクトリ下にコピーするだけです。

続いて、Packages/com.unity.automated-testing@0.8.1-preview.2/Runtime/RecordedPlayback/RecordingInputModule.csを開き、次の箇所を変更します。

internal void AddFullTouchData(TouchData td, bool setLastEventTime = false)
{
    playbackData.Add(td);  // ここを recordingData.Add(td); に書き換える

    if (setLastEventTime)
    {
        lastEventTime += td.timeDelta;
    }
}

Recorded Playback

以上の設定・修正を行った状態で、Automated QA | Automated QA Hub | Recorded Playbackを開き、Recordボタンで記録を開始します。 記録終了後に生成されるJSONファイルには、次のようにキー入力も記録されています。

Dキーを押して離した箇所の抜粋)

"touchData": [
{
    "pointerId": 0,
    "eventType": 5,
    "timeDelta": 1.9524928331375123,
    "position": {
        "x": 0.0,
        "y": 0.0
    },
    "positional": false,
    "scene": "Zone1",
    "button": 0,
    "waitSignal": "",
    "emitSignal": "",
    "keyCode": "D",
    "inputText": "",
    "inputDuration": 0.496268630027771,
    "objectName": "",
    "objectTag": "",
    "objectHierarchy": "",
    "objectIndex": 0,
    "querySelector": "",
    "objectOffset": {
        "x": 0.0,
        "y": 0.0
    }
},
{
    "pointerId": 0,
    "eventType": 9,
    "timeDelta": 0.0,
    "position": {
        "x": 0.0,
        "y": 0.0
    },
    "positional": false,
    "scene": "Zone1",
    "button": 0,
    "waitSignal": "",
    "emitSignal": "",
    "keyCode": "d",
    "inputText": "",
    "inputDuration": 0.496268630027771,
    "objectName": "",
    "objectTag": "",
    "objectHierarchy": "",
    "objectIndex": 0,
    "querySelector": "",
    "objectOffset": {
        "x": 0.0,
        "y": 0.0
    }
},

このファイルを指定して再生すると、キー入力による左右移動やジャンプが再現されました!

なお、マウスクリックも記録されますが、"keyCode": "Fire1" の入力として記録され、座標は常に { 0, 0 } となりますので注意してください。

Test Generation

続いてテストコード生成を試します。 3種類の生成方法がありますが*6、"Full Tests"の場合は"Use Simplified Driver Code"をオフにしたほうがよさそうです。

"Full Tests"かつ"Use Simplified Driver Code"がオンの場合、再生がスムーズでなくなります(はじめのほうのフレームが無視されている?)。

"Use Simplified Driver Code"がオフ、もしくは"Simple Tests"であれば、スムーズに再生されました。

所感

PCやコンソール向けの場合、素直にNew Input Systemを使うほうが自動化は楽なはずです。 また、Automated QAパッケージの開発が再開されたとして、レガシーなInput Managerのサポートを続けるのかは謎です。 したがって、この記事が役に立つことはない気がしますが、供養のため公開します。

*1:であればInput Systemと呼ばないでほしいところですが、ソースを見るとNew Input Systemもサポートしようとする形跡が見えます

*2:Input Systemサポート対象外です。このため3Dゲームのサンプルにはほぼ適用できません

*3:ドキュメントに書かれていなくて忘れがち

*4:ゲームコントローラ向けに一箇所だけGetAxisRaw()があります。これはサポート外なので、RecordableInputに置き換えても再生されません。なお、未サポートのメソッドはUnityEngine.InputにフォールバックされていますのでInputとしての振る舞いはキープされます

*5:ちゃんとビルドからストリップされるかは要検証

*6:詳しくは『Unity Automated QA攻略ガイド』参照

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。 サンプルコードを見たいのであれば、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しかインポートできません*2。 インポートしたらasmdefファイル内のアセンブリ名を変えていくとよいでしょう。

以下、各Exerciseの内容です。

  1. Running Tests: 最初のテストを書いて実行するもの。テスト対象にバグがあって修正するというものなので、テスト初心者の方は1_RunningTest_Projectから見ることをおすすめします
  2. Arrange, Act, Assert: 読みやすいテストの書きかたとして3Aを紹介*3
  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: テストメソッドの前後に処理を行なう方法*4
  7. PlayMode Tests: 再生モードでテスト実行する方法
  8. PlayMode Tests in Player: スタンドアロンプレイヤーでPlay Modeテストを実行する方法
  9. UnityTest Attribute: UnityTest属性による複数フレームにまたがるテストの例*5
  10. Long Running Tests: 実行に時間がかかるテストにCategory属性およびExplicit属性を指定して実行タイミングをコントロールする方法
  11. Scene Based Tests: Edit ModeテストでSceneファイルをロードしてScene内のGameObjectを検証する方法*6
  12. Build Setup and Cleanup: テストのビルド前後に処理をはさむ IPrebuildSetup および IPostBuildCleanupの使いかた。テスト対象のSceneがプロジェクトのScenes in Buildに無いときに追加している*7
  13. Domain Reload: Edit Modeテストでスクリプトコンパイルなどドメインリロードを挟むテストの書きかた*8
  14. Preserve Test State: ドメインリロードが発生するテストでは変数が失われるので、回避策としてSerializeField属性を使う例*9
  15. Test Cases: TestCase属性によるパラメタライズドテストの書きかた。本文ではTestCaseSource属性・Values属性・ValueSource属性にも触れられています
  16. Custom Attributes: NUnitのカスタム属性を定義する例*10
  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が参考になるでしょう*11

Reach wand test

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

Collision test

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

Asset change test

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

Scene validation test

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

Performance tests

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

まとめ

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

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

www.nowsprinting.com

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

www.nowsprinting.com

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

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

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

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

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

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

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

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

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

*10:ただし例として書かれているものはMaxTime属性でできるもの

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

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

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

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

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

Unity Test Framework v1.3で非同期テスト

Unity公式のユニットテストレームワークであるUnity Test Frameworkパッケージのバージョン1.3がリリースされました。

v1.2はスキップされ、v2.0での実装を予定されていた非同期テストのサポートが実装されています。

アップグレード方法

Package Managerウィンドウにv1.3が表示されれば*1そのままアップグレード可能です。 v1.3が表示されない場合、Packages/manifest.jsonファイルを直接開き、com.unity.test-frameworkのバージョンを1.3.0に書き換えます。

なお、前提UnityバージョンがUnity 2019.2から2019.4に上がっています。 依存パッケージであるcom.unity.ext.nunitも、v1.0.6からv2.0.3に上がっています*2

また以下の注意事項があります。現時点でのアップグレードは自己責任で。

  • 廃止されたAPIがあるため、例えばGraphics Test Frameworkコンパイルエラーを起こしています。これは意図的なものかどうか疑問で、今後修正される可能性もありそうです
  • Package Managerでエラーが出る(Unityバージョンによる?)。いくつかのバージョンで試しましたが、Samplesの表示が行われておらず、何らかの問題は出ていそうです

非同期テスト

これまでは非同期処理のテストはUnityTest属性をつけたコルーチンしかサポートされていませんでした。 v1.3からは、次のようにTest属性のテストとしてasyncメソッドを呼び出すことができます。

[Test]
public async Task 非同期テストの例_Taskをawaitできる()
{
    await Foo(1);
    var actual = await Bar(2);
    Assert.That(actual, Is.EqualTo(3));
}

private static async Task Foo(int id)
{
    await Task.Delay(200);
}

private static async Task<int> Bar(int id)
{
    await Task.Delay(200);
    return id + 1;
}

もちろんUniTaskも使用できます。

[Test]
public async Task 非同期テストの例_UniTaskをawaitできる()
{
    await UniTaskFoo(1);
    var actual = await UniTaskBar(2);
    Assert.That(actual, Is.EqualTo(3));
}

private static async UniTask UniTaskFoo(int id)
{
    await UniTask.Delay(200);
}

private static async UniTask<int> UniTaskBar(int id)
{
    await UniTask.Delay(200);
    return id + 1;
}

今回試したコードは、『Unity Test Framework完全攻略ガイド』サンプルプロジェクトにマージ済みです。 下記リンク先を参照してください。

github.com

また、SetUp/TearDown属性を付与したメソッドにもasyncキーワードを指定して非同期化することができます。 こちらもサンプルコードを参照してください。

github.com

参考

www.nowsprinting.com

www.nowsprinting.com

*1:されないこともあり謎。v1.3は実験的バージョンではないのですが…

*2:Unity Test Framework v2.0.1-exp.1ではv2.0.2でした

PlatformIO for CLionで #M5Stack へのuploadポートを環境変数で指定する

M5Stack Basic v2.6に搭載されているシリアル変換ICであるCH9102FのmacOSドライバ(v1.7時点)では、M5Stackが接続されているシリアルポートを明示的に指定しないでuploadしようとすると次のエラーで失敗します。

(snip)
Looking for upload port...
Auto-detected: /dev/cu.usbmodemXXXXXXXXXXX
Uploading .pio/build/m5stack-fire/firmware.bin
(snip)
A fatal error occurred: Failed to write to target RAM (result was 01070000: Operation timed out)
*** [upload] Error 2

本来接続すべき /dev/cu.wch* でなく /dev/cu.usbmodem* に接続しようとして失敗しています。 この事象および、回避方法としてuploadポートをplatformio.iniファイルに指定する方法が下記ブログで紹介されていました(たいへん助かりました)。

blog.magcho.com

しかし、シリアルポートをリポジトリに書き込んだり、それをM5Stackをつなぎ替えるたびに書き換えるのも面倒なので、別の手段を探ってみました。

検証環境

検証環境は次のとおりです。

  • macOS 11.2.3 (Big Sur)
  • CLion 2022.2.3
  • PlatformIO for CLion plugin 22.3739.54
  • M5Stack Basic v2.6

PLATFORMIO_UPLOAD_PORT環境変数

uploadポートは、グローバル環境変数 PLATFORMIO_UPLOAD_PORT で指定することもできます*1

uploadだけCLIで実行するのであれば、次のように指定できます。

PLATFORMIO_UPLOAD_PORT=$(ls /dev/cu.wch*) pio run --target upload --environment m5stack-core-esp32

しかしこれではテスト実行やデバッグ実行を考えると不便です。 そこで、.bashrcに次のように追加することで、uploadもCLionのGUIから実行できるようにしました。

export PLATFORMIO_UPLOAD_PORT=$(ls /dev/cu.wch*)

.bashrcが読まれるのは(uploadなどの実行時でなく)CLion起動時なので、設定後CLionの再起動が必要です。 また、M5Stackをつなぎ替えたときにもCLionの再起動が必要な点にご注意ください。

コード全体はこちらを参照

github.com

Run Configurationで環境変数を指定できるとよいのでは?

とはいえ、PlatformIO for CLion pluginではPlatformIO Coreつまりpioコマンドを実行していますので、Run Configurationで環境変数を指定できると便利そうです。

これを要望としてIssue Trackerに登録しましたので、類似の悩みをお持ちの方はvoteもしくは、より良い提案をコメントいただけると嬉しいです。

https://youtrack.jetbrains.com/issue/CPP-30672/Support-specify-environment-variable-on-run-configurationyoutrack.jetbrains.com

参考

www.switch-science.com

mag.switch-science.com

www.jetbrains.com

platformio.org

#C100 ありがとうございました

コミックマーケット100、無事終わりました。 ご購入いただいた方々、また、スペースにお立ち寄りいただいた方々、ありがとうございました。

ありがたいことに新刊既刊とも完売してしまい*1、ご購入いただけなかった方々には申し訳ありませんでした。 既刊はともかく新刊は少し余裕を持ったつもりでしたが、すみません。

新刊『Unity Test Framework完全攻略ガイド 第2版』は、数日中にPDF版、またAmazonKindle版およびPOD版をリリース予定ですので、もうしばらくお待ち下さい。 下記記事でアナウンスしていきます。

www.nowsprinting.com

既刊『Unity Automated QA攻略ガイド』のPDF版はBOOTHおよび技術書典マーケットでご購入いただけます。 またこちらもAmazonKindle版およびPOD版のリリースを検討しています。

www.nowsprinting.com

所感

一般参加チケット販売数はC99の1.5倍、第7波&台風8号で回避された方もいるはずですが、もう少し多く感じました。西はVTuberとかコスプレROMもあったので回遊している人が多かったのかもしれないですが。 なにより、一般入場時間が3段階あったせいか、午後になってもそれほど閑散とすることなく人が流れていて、休憩(&買いもの)タイミングが難しい回でした。

スペースでは、知り合いの方もそうでない方も、Unityのテストに関して色々お話できたりして*2楽しく過ごせました。 ここ数年失われている勉強会の懇親会の雰囲気を思い出します。

最後になりましたが、この機会・この場を作ってくださった準備会の皆様、ありがとうございました。 そして遅刻してすみませんでした…

C101予定

準備期間が短いのが悩みどころですが、申し込む方向で検討中です。 引き続きUnityのテスト系で、統合テスト(integration testing)にフォーカスした本の構想があるので恐らくはそれで。

ぜひ、サークル「いか小屋」をお気に入り登録してお待ち下さい。

*1:既刊13:45ごろ、新刊14:25ごろ

*2:いただいたスペースがお誕生日席の外側で余裕あったためできたことです。また、距離を取ってお互いマスクをしていたとはいえ、感染症対策的には好ましくない行為ではありますが

Unity Test Framework完全攻略ガイド 第2版

Unityの標準テストフレームワークであるUnity Test Frameworkパッケージの解説本をコミックマーケット100の1日目(土曜日)西そ06b*1いか小屋」で頒布します。

昨年の技術書典11で頒布した第1版をベースに、テストダブルやテスト技法に関するセクションなどへの加筆修正のほか、プレビューリリースとされているUnity Test Frameworkバージョン2の変更点についても付録として収録しています。

想定読者

UnityでC#スクリプトを書けるレベルのソフトウェアエンジニア(プログラマー)を想定しています。 UnityやC#言語自体の解説はしていません。

ユニットテストに関しては入門レベルからカバーしています。

目次の紹介

各章の内容は次のとおりです。

第1章 テストとは何か

「テスト」と、ゲーム業界で使われる「デバッグ」という言葉の違いから、テストのターゲットに応じた考えかた、どのようなテストを自動化すべきか等。

第2章 Unity Test Frameworkの基本

Unity Test Frameworkパッケージを使ってユニットテストを書き、実行する手順を、順序立てて説明しています。 フォルダ(アセンブリ)構成や命名の指針も紹介しています。

第3章 Edit Modeテスト

主にロジックのテストに利用できるEdit Modeテストの特徴と、Edit Modeテスト固有の機能について。

第4章 Play Modeテスト

よりUnityプレイヤーに近い環境で動作させられるPlay Modeテストの特徴、Unityエディターおよびプレイヤーでの実行方法について。

第5章 非同期処理のテスト

コルーチンやUniTaskによるasyncメソッドのテストについて。

第2版では、Unity Test Framework v2.0でasync/awaitが使用できるようになることを踏まえ、表記の見直しを行ないました

第6章 アサーション

NUnit3の制約モデル(Assert.That)によるアサーション(テスト実行結果の検証)について、検証対象や目的に応じた最適な書きかたやTips、アンチパターンを紹介。

第7章 テストダブル

テスト対象が何らかのコンポーネントに依存しているとき(内部で生成した疑似乱数やサーバからのレスポンスに応じて結果が変わるなど)、その依存コンポーネントを偽物(スタブ、スパイ、モックなど)に置き換えてテストするテクニックの紹介。

第2版では、シーケンス図の見直し、サンプルコード掲載*2、NSubstituteについて詳細化を行ないました

第8章 パラメタライズドテスト

ひとつのメソッドを引数を様々に変えてテストしたいとき、NUnit3のTestCase属性・TestCaseSource属性・Values属性・ValueSource属性を使ってこれを実現する方法。

第9章 Unity Test Framework Tips

Unity Test Frameworkに備わる機能の紹介。 許容誤差付きのアサーション(EqualityComparer)、GCメモリアロケーション検知(AllocatingGCMemory)、ログ出力の検証(LogAssert)、テストの前処理・後処理(SetUp/TearDown属性, OneTimeSetUp/TearDown属性, PrebuildSetup/Cleanup属性, ICallbacks/IErrorCallbacksインタフェース)、アセットのロード、実行プラットフォーム制限(UnityPlatform属性)、カテゴライズ(Category属性)、タイムアウトの指定(Timeout属性)、MonoBehaviourのテストなど。

第2版では、UnitySetUp/TearDown属性のセクションを追加しました*3

第10章 Sceneを使用するテスト

Edit Modeテスト・Play Modeテスト(エディター実行)・Play Modeテスト(プレイヤー実行)それぞれで、Sceneファイルをロードしてテストに使用する方法。 "Scenes in Build"に含まれないSceneをロードする方法も紹介しています。

第11章 UPMパッケージのテスト

Unity Package manager(UPM)パッケージのテストを実装・実行する方法。

第12章 テストの実行方法

UnityエディターのTest Runnerウィンドウ、Jet Brains Rider、コマンドラインからのテスト実行方法・オプションの紹介。

第13章 コードカバレッジ

Unity Code Coverageパッケージを用いてコードカバレッジ(テストがプロダクトコードのどの部分をカバーしているかの指標)を採取する方法。 また、RiderのdotCoverプラグインの紹介。

第14章 テスト実装のヒント

壊れやすい「実装のテスト」ではなく、変更に強い「仕様のテスト」を書くためのアプローチを紹介しています。 テストケースを導出するためのテスト技法(同値分割法・境界値分析・デシジョンテーブル・組み合わせテスト)、再現テスト、テスト駆動開発(TDD)。

第2版では、各テスト技法のモデル図、状態遷移テストおよび学習テストのセクションを追加しました

付録A JetBrains Rider Tips

IDEにRiderを使う場合の、コグニティブ複雑度の計測(CognitiveComplexityプラグイン)、テスト用Live Templateの紹介。

付録B OpenUPM-CLI

本書で紹介しているUPMパッケージをUnityプロジェクトにインポートするのに便利なopenupm-cliコマンドの紹介。

付録C Unity Test Framework v2.0

第2版で追加しました。現在プレビュー中であるv2.0の主な変更点をまとめています*4

変更点を特記していない章も、前提バージョンの変更や記述の見直しなどを実施しています。 ページ数では134から152と18ページ増ですが、原稿の行ベースで見ると約35%書き換わっています(git diff調べ)。

サンプルコード

サンプルコードは引き続き下記リポジトリを参照してください。

github.com

表紙について

C99の『Unity Automated QA攻略ガイド』に続き、りょふ彦(@ryofu1323)さんにファンタジーRPG風ユニティちゃんをお願いしました。

デフォルメも等身もかわいく描いていただけて、大変ありがたいです。

信販売・電子版について

[8/17] BOOTHにて電子版のアップデート配信を開始しました。 物理本は在庫なしです。ご希望の方は「入荷お知らせメールを受け取る」をクリックしてお待ち下さい。需要次第で増刷を検討します。

ikagoya.booth.pm

[8/22] 技術書典オンラインマーケットにて電子版のアップデート配信を開始しました

techbookfest.org

なお、近日中にAmazonKindle版およびPOD版のリリースも予定しています。

その他

第1版の内容についてはこちらの記事を参照してください。

www.nowsprinting.com

既刊の『Unity Automated QA攻略ガイド』も若干数ですが持っていきます。 内容はこちらの記事を参照してください。

www.nowsprinting.com

*1:また日本Androidの会Unity部さんのお隣です! UNIBOOK14のついでにお立ち寄りください

*2:サンプルコードリポジトリには例がありましたが、今回一部変更した上で本文にも掲載しています

*3:なぜか漏れていました…

*4:元々の予定ではUnity 2022.2から正式採用のはずだったのですが、5月に延期がアナウンスされました