やらなイカ?

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

Unity Test Framework完全攻略ガイド

[2022/8/10] コミックマーケット100で第2版を頒布します。こちらの記事を参照してください

www.nowsprinting.com


Unityの標準テストフレームワークであるUnity Test Frameworkパッケージ*1の解説本を技術書典11向けに上梓しました。 ギリギリ審査が通って閉幕までに間に合いました(間に合ってない

techbookfest.org

BOOTHにも置いています。

ikagoya.booth.pm

内容は、Edit Mode/ Play Modeテストの特性、非同期テスト、アサーション(NUnit3の制約モデル)、カスタムアサーション、テストダブル、パラメタライズドテスト、Sceneやアセットのテスト、その他Tips。 と、ユニットテストとその周辺だけに絞った*2のですが135ページもあるこわい。

対象バージョンは Unity Test Frameworkパッケージ v1.1.27、Unity 2020.3.12f1、JetBrains Rider 2021.1です。 とはいえ、中心はUnity Test Frameworkパッケージですので、本書で紹介するほとんどの機能はUnity 2019.2以降で動作するはずです*3

また、Riderについてはテスト実行方法やTipsの紹介程度ですので必須ではなく、Visual StudioVisual Studio CodeVS Code)、もしくはVimなど、使い慣れたIDEをお使いいただけば大丈夫です。

ソフトウェアテストに関する用語は、原則としてJSTQB技術委員会による『ISTQBテスト技術者資格制度 Foundation Level シラバス 日本語版 Version 2018V3.1.J03』および『ISTQB GLOSSARY Ver3.2(日本語版)』から解説を引用しつつ使用しています。 またテストダブルなどユニットテストの技法に関しては『xUnit Test Patterns』(xUTP)に準じています。

サンプルコードは下記リポジトリで公開しています。NUnit3の制約全網羅したりと、書籍よりむしろこっちが本体かもしれない。

github.com

目次の紹介

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

第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メソッドのテストについて。

第6章 アサーション

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

第7章 テストダブル

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

第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のテストなど。

第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)。

付録A JetBrains Rider Tips

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

付録B OpenUPM-CLI

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

付録C NuGetForUnity

本書で紹介しているNuGetパッケージをUnityプロジェクトにインポートするのに便利なNuGetForUnityの紹介。

執筆を支える技術

以下、執筆に使用したツール類です。感謝しかない。

Re:VIEW

github.com

github.com

書名が長いのでこの記事を参考に大扉の折返しを調整しています。 kyabe.net

textlint

github.com

今回使用したルールは以下。

$ npm install --save-dev textlint \
textlint-rule-preset-ja-spacing \
textlint-rule-preset-ja-technical-writing \
textlint-filter-rule-comments \
textlint-filter-rule-allowlist \
textlint-rule-prh \
textlint-rule-abbr-within-parentheses \
textlint-rule-common-misspellings \
textlint-rule-spellchecker \
textlint-plugin-review

prh

github.com

prh (proofreading helper) は、表記ゆれなど校正を支援してくれるツールです。 ビルトインで十分に実績のあるルールが提供されていますが、今回執筆を進めながら、Unity、C#、JetBrains、ISTQB日本語版、xUTPに関する用語を追加しました。

追加したルールは下記リポジトリで公開しています。本書の範囲だけなので網羅にはほど遠いのですが、今後も育てていければと。

github.com

スクリーンショット用にウィンドウサイズを整えるAppleScript

スクショのサイズが統一されていないのは嫌なので、次のスクリプトでリサイズして撮影しました。

Unity用

Rider用

所感

元々はC98(2020年GW)に出そうと着手したのが、コミケ流れたり忙しかったりで1年半かかってしまいました。 当時は制限事項として書こうとしていたものが今は修正されていたり、Unity Test Frameworkも日々進歩していることをここ数週間の追い込みで実感したりできました。

本の執筆は5年ぶり、同人誌は初でした。 Re:VIEWやtextlint、prhなどツールが整っていて、手軽にそれなりに見られるものがレンダリングできてしまうのは素晴らしいですね。 もちろん、カスタマイズやレイアウトなど凝りたくなるとそこはプロの技が必要なわけですが。

ちなみに、審査に数日と聞いていたので開催期間中に間に合うか不安だったのですけれど、半日くらいで爆速審査していただけました。 技術書典スタッフの方々、本当にありがとうございました。

技術書典11は本日いっぱい開催です。電子書籍は明日以降も購入できますが、よい機会なので色々見てまわってはいかがでしょうか。

techbookfest.org

[追記]技術書典「第4回 刺され!技術書アワード」のファイナリストにノミネートされました! *4

*1:パッケージ化される前の名称はUnity Test Runner

*2:テスト戦略や統合テスト向けツールやらCIや静的解析などのドロップしたネタは改めて供養したい

*3:サンプルコードはCI上でUnity 2019 LTS〜2022.1でテストをパスしています

*4:「第4回 刺され!技術書アワード」は技術書典12で行われたものです。本書は技術書典11の第3回にはエントリしておらず、こちらにエントリしました

#PLATEAU 3D都市モデルの水ぜんぶ抜く大作戦

国土交通省 Project PLATEAU で、横浜市の3D都市モデルが公開されました。 このデータを使用する際、水面にあたる部分に面が張られており使いづらかったので*1Blenderで水面をすべて削除して、改めて水面用のメッシュを用意しました。 本記事はこの手順メモです。

3D都市データファイルをBlenderにインポート

今回使用したのは、横浜市(2020年度)のOBJデータです*2。 こちらをダウンロード・解凍して、目当てのエリアのデータをBlenderにインポートします。今回使用したのはBlender 2.93です。

www.geospatial.jp

Project PLATEAUのOBJデータは以下の4つに別れています。それぞれフォルダ内にエリアごとのファイルがありますが、今回は、みなとみらいエリアを含む 533915 のみ使用します。

  • bldg(建築物)
    • LOD1(全域)
    • LOD2(一部のみ)
  • dem(地形)
  • tran(道路)

なお、インポート時はTransformを Y Forward, Z Up に設定します。 また、原点が離れた位置に設定されているので移動しておくと便利です*3

今回加工するdemは次のように水面まですべて面が張られています。

ランドマークタワー近辺を拡大すると、地面には細かく頂点があり、水面は地面のキワから対岸などに長い辺が伸びて面が張られていることがわかります。

水面を削除する

地面と水面のキワにあたる頂点は、実際には測量された地面の端と思われ、このあたりでZ = 2m〜2.2mほどあります。 頂点の高さで水面を判断することは難しいので、「辺の長さが20m以上のものは水面」と判断して削除するPythonスクリプトを書いて処理します。

該当部分だけ抜粋すると次のコードです。

def expose_water_surface(target_pattern=r"^\d+_dem_\d+$", edge_length=20.0):

(snip)

    pattern = re.compile(target_pattern)
    for obj in bpy.context.scene.objects:
        if not pattern.match(obj.name):
            continue

(snip)

        for edge in mesh.edges:
            if edge.calc_length() >= edge_length:
                mesh.edges.remove(edge)

(snip)

これをBlenderのScriptsワークスペースで開き、実行します(詳しくは後述)。

処理後はこうなりました。左上のくぼみはドックヤードガーデンなので、削除されなくて正解です。

この時点で俯瞰して見ると、海上に格子状に頂点が残っています。

これはエリアの切れ目に置かれた頂点ですので、面積0の面および孤立した頂点というルールで削除します。 この処理は、次のブログ記事にあるスクリプトをほぼそのまま使用しました。

bluebirdofoz.hatenablog.com

削除後がこちら。まだ細かいゴミは残っていますが、自動処理はここまでとしました*4

このデータをFBX形式でエクスポートしてUnityにインポート、clusterワールドとして公開したのがこちらです。水色は改めて追加した水面メッシュです*5

cluster.mu

今回使用したスクリプトはこちらに公開しています。 Blender初心者の書いたコードなので無駄なステップがあるかもしれませんし事故を起こす恐れもあります。ご利用は自己責任で、バックアップを必ず取ってから使ってください。

github.com

Blender上でPythonスクリプトを実行する方法

以下は補足です。

Blender上でPythonスクリプトを実行するには、まずScriptingワークスペースを選択し、中央のエディタ上部にあるOpen Textアイコンで実行するPythonスクリプトを開きます。 次いで、Run Scriptアイコンで実行します。

macOSの場合はGUI上にログが出ないため*6、実行ログを参照するためにはコマンドプロンプトからBlenderを実行する必要があります。

PyCharmでBlender向けスクリプトを書く

新規プロジェクト作成の際、Base interpreterにはBlenderが内包しているPythonを指定します。 Homebrewでインストールした場合、次のパスにあるはずです。

/Applications/Blender.app/Contents/Resources/2.90/python/bin/python3.7m

続いて、BlenderAPIであるbpyパッケージのFakeをインストールします。Fakeなので実行はできませんが、コード補完が効くようになります。

Preferences... | Python Interpreter を開き、 fake-bpy-module-x.xx を追加します。末尾はBlenderバージョンと合わせてください。

github.com

リダクションとFBXエクスポート設定

前述のように地表には約5m間隔で頂点が配置されており、特にみなとみらい地区のような平地では贅沢です。 今回は、demにのみDecimateモディファイアを追加、Ratioは0.01に設定して、△約3,000,000から30,000に削減しました*7

モディファイアを含めたFBXエクスポート設定は以下のようにしています。

  • Object Types: Meshのみ選択
  • Transform
    • Apply Scalings: FBX All
    • -Z Forward, Y Up(FBXのデフォルト)
  • Geometry
    • Apply Modifiers: on
  • Armature
  • Bake Animation: off

ファイルサイズは、モディファイアなしで約110MBだったところ、42.3MBになりました。

参考

bluebirdofoz.hatenablog.com

zenn.dev

*1:横浜市の3D都市モデルを基準にしています。他の都市にはあてはまらない可能性がありますのでご注意ください

*2:先に公開されていた東京都23区はFBX形式のデータが提供されていましたが、横浜市ではCityGMLとOBJのみ提供されています

*3:エリアの中央もしくはVRChat/clusterなどのワールドで使用するのであればスポーン地点など

*4:本来はここから温かみのある手作業で消していきますが、今回は手作業なしでフィニッシュしました

*5:正しく処理されたはずのドックヤードガーデンに水面が張られているのは、一律平面の水面メッシュを追加したためです。そのうち対処しなければ

*6:調べた範囲では

*7:元町方面を見るとだいぶカクカクしているのがわかります

Unity Automated QAのRecorded Testing機能 トラブルシュート

Unity Automated QA パッケージのRecorded Testing機能を試していて遭遇したトラブルと解消方法をまとめます。 バージョンは 0.2.0-preview.3 および 0.3.0-preview.8*1 で確認しています。

Recorded Testing機能とは、UnityエディタのPlay modeでuGUIの操作を記録したjsonファイルをPlay modeテストとして実行できる機能です。

Unity Automated QAパッケージ全体については先のエントリ参照。

www.nowsprinting.com

[12/26追記]v0.8.1対応の『Unity Automated QA攻略ガイド』をコミックマーケット99で頒布します。詳しくはこちらの記事を参照してください

www.nowsprinting.com

FileNotFoundException: Could not find config.json

テスト実行時、下記スタックトレースが出て失敗するケース。

FileNotFoundException: Could not find file "/Users/***/Library/Application Support/DefaultCompany/UnityTestFramework/config.json"
System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) (at <fb001e01371b4adca20013e0ac763896>:0)
(snip)
System.IO.File.ReadAllText (System.String path) (at <fb001e01371b4adca20013e0ac763896>:0)
Unity.RecordedTesting.Manager.GetDeviceFarmConfig (Unity.RecordedTesting.DeviceFarmOverrides dfOverrides) (at Library/PackageCache/com.unity.automated-testing@0.2.0-preview.3/RecordedTesting/Runtime/Manager.cs:31)
Unity.RecordedTesting.TestResults.RunStarted (NUnit.Framework.Interfaces.ITest testsToRun) (at Library/PackageCache/com.unity.automated-testing@0.2.0-preview.3/RecordedTesting/Runtime/TestTools/TestResults.cs:33)

これは、ローカル環境でテスト実行しようとしているのに、AWS Device Farmで実行するルートに入っているため発生しています。

Edit | Project Settings... を開き、Playerタブ、Other Settings下にあるScripting Define Symbolsの中に CLOUD_TEST_UTF シンボルが定義されていれば、それを削除すれば解消します。

Cloud Test Runnerウィンドウを開いて操作しようとした際にシンボルが設定されたままになっていたようです。

SetUp : System.Reflection.ReflectionTypeLoadException

テストのSetupですべてのアセンブリから型情報を取り出している処理があるのですが、型を含まないアセンブリでこの例外が出ています。

CanPlayToEnd (3.571s)
---
SetUp : System.Reflection.ReflectionTypeLoadException : Exception of type 'System.Reflection.ReflectionTypeLoadException' was thrown.
---
--SetUp
  at (wrapper managed-to-native) System.Reflection.Assembly.GetTypes(System.Reflection.Assembly,bool)
  at System.Reflection.Assembly.GetTypes () [0x00000] in <fb001e01371b4adca20013e0ac763896>:0
  at Unity.RecordedTesting.RecordedTesting.GetAllRecordedTests () [0x00023] in /Users/****/Documents/UnityTestWorkspace/Library/PackageCache/com.unity.automated-testing@0.2.0-preview.3/RecordedTesting/Runtime/RecordedTesting.cs:55
(snip)

遭遇したアセンブリMicrosoft.CodeAnalysis.Scripting で、これはImmediate Window (com.unity.immediate-window) パッケージの依存先になっています。 今回はImmediate WindowパッケージをPackage Managerから削除することで解消しましたが、Automated QA側で対応されるまでは他のアセンブリで発生する恐れもあります。

Scene couldn't be loaded because it has not been added to the build settings or the AssetBundle has not been loaded

Recorded Testingでは、再生しようとするjsonに記録されているSceneをロードしてから操作を開始します。 しかし対象のSceneがビルド設定のScenes in Buildに入っていない場合、この例外が発生します。

SetUp : System.NullReferenceException : Object reference not set to an instance of an object
SetUp : Unhandled log message: '[Error] Scene '***' couldn't be loaded because it has not been added to the build settings or the AssetBundle has not been loaded.
To add a scene to the build settings use the menu File->Build Settings...'. Use UnityEngine.TestTools.LogAssert.Expect

ビルドに含めるSceneであればScenes in Buildに含めればよいのですが、テスト専用やアセットバンドルに格納するものは別の手段でロードする必要があります。

Unityエディタでの実行であれば、SceneManager.LoadSceneAsyncでなくEditorSceneManager.LoadSceneAsyncInPlayModeを使うことで回避できます。

Standalone playerでの実行では、テスト実行前のビルドにフックするITestPlayerBuildModifierを実装して、ビルド対象Sceneを書き換えることで回避できます。

実装例はこちらを参考にしてください。 github.com

いずれの問題もForumで報告済みなので、そのうち対応されるはず。

参考

docs.unity3d.com

forum.unity.com

*1:本稿執筆時点でPackage Managerからはインポートできますが、マニュアルサイトには未反映

Unity Automated QA雑感

Unity Automated QA パッケージが公開されました。 まだアルファリリース (0.2.0-preview.3) ですが、少し触ってみたメモ。

[12/26追記]v0.8.1対応の『Unity Automated QA攻略ガイド』をコミックマーケット99で頒布します。詳しくはこちらの記事を参照してください

www.nowsprinting.com

概要

Unityエディタ上で動く、uGUI操作のキャプチャ&リプレイ機能です。 Required: Unity 2019.4+

操作記録はjsonで保存され、エディタ上で再生できます。 また、Play mode testsに組み込んで実行でき、さらにAWS Device Farm上のAndroid端末で実行することもできます。

細かいところはまだ発展途上という感ですが、再生機能がかしこくなってくれればそれ単独で使いではありそうですし、 コンポジット機能が実用的になってくれれば(具体的にはuGUI以外も扱えるようになれば)Unityアプリの統合テストフレームワークとして有力になりそうです*1

以下、検証したときのメモです。

Recorded Playback

  • Window | Automated QA | Recorded Playback でウィンドウ表示
  • RecordクリックでPlay modeになり、StopクリックまでのuGUI操作がjsonに記録される
  • 記録したjsonはリスト表示され、Playクリックで再生
  • jsonファイル名はデフォルトでタイムスタンプ、リネーム可能
  • Assertの機構はない
  • 対象オブジェクトが無いなど操作できない場合、コンソールに Warning Error *2 メッセージを出して再生が継続される
  • 実行時にスクショを取っている(~/Library/下に出力され、参照するUIは無い)

jsonフォーマットについて

  • 時間(timeDelta)、座標、object name, tag, hierarchy, offset が記録されている。いい感じに再生時に解釈してくれていることを期待
  • イベントはpointer-down/upで記録しているので、長押しやドラッグも表現できている
  • ButtonのTextやImageは(要するに子オブジェクトまでは)拾っていない
  • idも保持していない。都度変わるので保存しても仕方ないから?
  • Sceneも記録されているがRecorded Playbackでは使用されない(PlayでそのSceneを開いたりはしない)。後述のRecorded Testing機能で使用される

Composite Recordings

  • Window | Automated QA | Advanced | Composite Recordings でウィンドウ表示
  • 複数の操作記録jsonを選択し、つなげたjsonを生成(マージされるのでなく各jsonをポイントするjsonを生成)
  • 部分操作を記録できる(上記Recorded PlaybackだとPlay modeのライフサイクルでしか撮れないので)
  • こちらもAssertの機構はない
  • 将来的に、記録した操作だけでなくC#スクリプトやML-Agentsのエージェントを組み込めるようにしたいとのこと

Recorded Testing

  • Tools*3 | Automated QA | Generate Recorded Tests で、 Assets/AutomatedTesting/GeneratedTests下にPlay modeテストコードが出力される
  • asmdefも作られる
  • テストコードは操作記録jsonと1:1で、中身はjsonを読んで再生している。再生終了後にAssertを自分で追加することは可能
  • テストケースごとに、jsonに記録されているSceneをロードしてから再生してくれる
  • 対象オブジェクトが無いなど操作できない場合、コンソールに Warningメッセージを出して再生が継続される(Recorded Playbackウィンドウでの再生と同様) Errorログを出力して再生は継続されるが、このログのためテストはFailする *4

生成されるテストコードの例

[UnityTest]
[RecordedTest("Recordings/composite-recording-2021-04-19-T01-05-01.json")]
public IEnumerator CanPlayToEnd()
{
    yield return RecordedTesting.TestPlayToEnd();
    Assert.IsTrue(true);
}

この機能で遭遇したエラーとその回避方法はこちらのエントリを参照。

www.nowsprinting.com

Running Recorded Tests on a Cloud Device Farm

  • AWS Device Farm上のAndroid端末でもテスト実行できる*5AWSとの直接契約・操作は不要
    • アーリーアクセス機能
    • 2021/6まで、Unity Proアカウントに100hのクラウドテストを無料トライアル
    • 以降 $10/device/hour *6 *7
  • アップロードなどのUIは実装されている(権利がなくて未検証)

参考

docs.unity3d.com

forum.unity.com

blogs.unity3d.com

*1:到達点は統合テストだと思うので、QAという名前は違和感ありますが。それはそれ

*2:v0.3.1で変更された

*3:なぜ一箇所にまとめてくれないのか

*4:v0.3.1で変更された。もし操作不能を無視してテストを成功させたければ、LogAssertを使えばいい

*5:Automated QAのテストに限らず、and other Unity testsが実行可能。であればパッケージ分けてほしかった

*6:AWS Device Farmを直接使っても $0.17/device/minute == $10.2/device/hour なのでむしろ少し安い。see: https://aws.amazon.com/device-farm/pricing/

*7:表記がhourなのでhour単位に切り上げられる恐れはあるかも。要確認

Unity 2020.2時点のRoslyn Analyzerサポート状況まとめ

Unity 2020.2でRoslynアナライザによる静的解析が動作するようになりました。しかし、まだ色々と制限があるようなので現時点のサポート状況を検証してまとめてみました。

検証に使用したプロジェクト も公開していますので、認識違い等あれば教えていただると嬉しいです。

Unity 2020.2以降の主な更新内容

Unity 2020.3.4

  • Packages下(Embedded package, Local package, Package from UPM registry/ Git URL)かつAssembly Definition File (.asmdef) 管理下のアナライザDLLが認識されるようになった
  • 通常のコンパイルステップで診断が実行されるようになった(以前はファイル更新かReimport契機)

Unity 2020.3.6

  • IDEsプラグインパッケージの対応バージョン*1との組み合わせで、IDEsでもAnalyzer Scope(asmdefの依存関係を反映した適用範囲)が機能するようになった(2021.1.2からのバックポーティング)

Unity 2021.1.0

  • Rulesetの変更が即時反映されるようになった(Unity 2020ではReimportが必要)
  • BatchmodeでビルドするときにもRulesetが反映されるようになった
  • Roslyn AnalyzerがあるとDeterministic Compilationが効かなくなる問題*2が修正された*3
  • Roslyn Analyzerによる重要度Errorの検出がある状態でAssets | Open C# Projectを実行してもslnおよびcsprojファイルが生成(更新)されない問題が修正された*4

Unity 2021.1.2

  • IDEsプラグインパッケージの対応バージョンとの組み合わせで、IDEsでもAnalyzer Scope(asmdefの依存関係を反映した適用範囲)が機能するようになった*5

Unity 2021.2.0

  • 内包するMicrosoft.CodeAnalysis.CSharpバージョンがv3.5からv3.9に変更され、Microsoft.CodeAnalysis.CSharp v3.6以降を使ってビルドされたアナライザ*6が動作するようになった

Unity 2022.1.0

  • 内包するMicrosoft.CodeAnalysis.CSharpバージョンがv3.9からv3.11に変更された [2024-02-29 追記]

アナライザのスコープ/ .csprojへの反映

Unity 2020.2+ JetBrains Rider Editor v2.0.6+ Code Editor Package for Visual Studio Code v1.2.0+ Code Editor Package for Visual Studio v2.0.7
Analyzer Scope (asmdefの依存関係を反映) *7 *8 → ○*9 *10 → ○*11 *12 → ○*13
Assetsフォルダ下のDLLs - → ○*14
Embedded package下のDLLs *15 ☓ → ○ *16 - → ○*17
Local package, UPM registry or Git URLから取得したPackage下のDLLs ☓ → ○ *18 *19 → ○*20 *21 → ○*22 - → ○*23

Unity 2020.2+ 列は、Unity Editor GUIで診断実行する際のアナライザのスコープ(適用範囲)について。

その他は、Assets | Open C# Project でIDEを開くときに生成される.csprojへの反映状況です。 JetBrains Rider Editorはv2.0.6で、Visual Studio Code Editorはv1.2.0で、Unityエディタ向けに設定されたRoslynアナライザのDLLがあると.csprojに <Analyzer> ノードが追加されるようになっています。

Unityエディタ (GUI) / IDEでの診断実行

Unity 2020.2+ JetBrains Rider 2021.1 VSCode VS 2019
診断実行 *24
重要度設定(.ruleset) *25 ☓ → ○*26
重要度設定(.editorconfig)
重要度設定(IDE独自) - *27
診断の抑止(シンボル) *28
診断の抑止(行)*29 ☓ → ○ *30
特定のアナライザ*31 ☓ → ○ *32

空欄は未検証です

CLIでの診断実行

Unity 2020.2+ Batchmode JetBrains ReSharper CLT 2021.1 dotnet build Standalone Analyzer
診断実行 *33 *34
重要度設定(.ruleset) ☓ → ○ *35 -
重要度設定(.editorconfig) -
重要度設定(IDE独自) - -
診断の抑止(シンボル) -
診断の抑止(行) -

空欄は未検証です

所感

もうなにも信じられない

参考

docs.unity3d.com

forum.unity.com

github.com

docs.microsoft.com

docs.microsoft.com

*1:JetBrains Rider Editor v3.0.9+, Code Editor Package for Visual Studio Code v1.2.4+, Code Editor Package for Visual Studio v2.0.11+

*2:検証プロジェクト https://github.com/nowsprinting/DeterministicCompilationWithRoslynAnalyzer

*3:Unity 2020.3.26f1では修正されていない

*4:Unity 2020.3.27f1では修正されていない

*5:Unity 2020.3.6にバックポートされた

*6:Microsoft.Unity.AnalyzersやNUnit.Analyzers

*7:https://docs.unity3d.com/2020.2/Documentation/Manual/roslyn-analyzers.html

*8:asmdefの依存関係に関わらず、全てのアナライザが全ての.csprojに設定される

*9:v3.0.9で対応。ただしUnity 2020.3.6f1以降もしくは2021.1.2f1以降も必要

*10:asmdefの依存関係に関わらず、全てのアナライザが全ての.csprojに設定される

*11:v1.2.4で対応。ただしUnity 2020.3.6f1以降もしくは2021.1.2f1以降も必要

*12:常に /Applications/Visual Studio.app/Contents/Resources/lib/monodevelop/AddIns/MonoDevelop.Unity/Analyzers/Microsoft.Unity.Analyzers.dll だけが追加される

*13:v2.0.11で対応。ただしUnity 2020.3.6f1以降もしくは2021.1.2f1以降も必要

*14:v2.0.11で対応。ただしUnity 2020.3.6f1以降もしくは2021.1.2f1以降も必要

*15:https://docs.unity3d.com/2020.2/Documentation/Manual/roslyn-analyzers.html に記述のある、Plugin Inspectorでラベルの設定がPackages下のDLLでは表示されないため、Assets下でラベル設定した後にPackages下に移動して検証しています

*16:Unity 2020.3.4で解消(Release notesおよびIssue trackerには記載なし)。なお、Unity 2020.3.3以前でもasmdef下にないDLLは有効

*17:v2.0.11で対応。ただしUnity 2020.3.6f1以降もしくは2021.1.2f1以降も必要

*18:Unity 2020.3.4で解消(Release notesおよびIssue trackerには記載なし)。なお、Unity 2020.3.3以前でもasmdef下にないDLLは有効

*19:.csprojに<Analyzer>ノードは追加されるが、パスがUnityエディタ上のPackages下を指すためDLLの実体が無く無効

*20:v3.0.9で対応

*21:.csprojに<Analyzer>ノードは追加されるが、パスがUnityエディタ上のPackages下を指すためDLLの実体が無く無効

*22:v1.2.4で対応。ただしUnity 2020.3.6f1以降もしくは2021.1.2f1以降も必要

*23:v2.0.11で対応。ただしUnity 2020.3.6f1以降もしくは2021.1.2f1以降も必要

*24:Unity 2020.2では診断は当該ファイルのコンパイルもしくはReimportの契機でのみ実行されたが、Unity 2020.3.4で通常のコンパイルステップで動作するよう変更された

*25:Unity 2020では変更を反映するのにReimportが必要だったが、Unity 2021.1でRuleset適用タイミングを早める修正が入ったことによりこの問題も解消

*26:Rider Editor package v3.0.9で対応

*27:Preferences...で設定して.sln.DotSettingsに保存

*28:SuppressMessageアトリビュート

*29:#pragma warning disable/restoreディレクティブ

*30:Rider 2021.1以前ではクイックフィックス候補に"// ReSharper disable"が出るが、Roslynアナライザの診断結果には無効。Rider 2021.2 EAP1以降で"Disable with #pragma"が選択可能になった

*31:NUnit.Analyzersが適用されない。要因は不明

*32:Unity 2021.2で解消

*33:ビルドログに出るのでパースが必要

*34:https://youtrack.jetbrains.com/issue/RSRP-480257 voteしましょう

*35:Unity 2021.1で解消

『ソフトウェア品質を高める開発者テスト アジャイル時代の実践的・効率的なテストのやり方』レビュー

昨日発売された『ソフトウェア品質を高める開発者テスト アジャイル時代の実践的・効率的なテストのやり方』、ざっくりと読んだので簡単にレビューします。

対象読者

まず対象読者について。タイトルにある「開発者テスト」や「ユニットテスト」というものを実践している方はもちろん、言葉は知っていて良いテストを書きたいを思っている方などには 向きません *1

そうではなく、旧来の、開発の後工程としてテストを実施し、バグを潰しきれずに疲弊している組織の方におすすめしたい書籍です。

早期工程でのバグ検出・品質作り込み(本書では「上流品質向上」と表現)、ユニットテストリファクタリング、CI(継続的インテグレーション)といったモダンな開発手法に馴染みのない方にとって、一通りの知識をこの一冊でざっくり得られるはずです。

おすすめできる点

  • はじめにモチベーションとして、上流品質向上やShift Leftの効果についてしっかり語られている
  • コードカバレッジについて、ステートメントカバレッジ (C0) とブランチカバレッジ (C1) の違いについて詳しく書かれている
  • サイクロマティック複雑度(本書では単に「複雑度」や「McCabe数」と表現)について、詳しく書かれている
  • Googleのバグ予測(修正回数の多いファイルはバグ混入率が高い)に触れられている
  • テストケースを作るためのテスト技法について触れられている(ただし境界値テストと状態遷移テストのみ。これを目的にするのであれば後述する別書籍をおすすめします)
  • システムテストなど後工程のテストにも言及、全体を俯瞰できるはず
  • Android Studioを使ったユニットテスト、コードカバレッジ採取、Circle CIによるCIなど、実践的なサンプルやスクリーンショット(ただし巻末の1割程度のボリューム)

おすすめできない点

  • 用語が独自なので、この書籍を読んだ次のステップで調べたり、他のテストエンジニアと交流する段階でギャップが出そう。本書を読んだ後、 JSTQB認定テスト技術者資格-シラバス(学習事項)・用語集- などを参照してテスト用語の認識を合わせたほうがよさそうです *2 *3
  • リファクタリングの根拠がファイルの大きさとサイクロマティック複雑度のみなので、もう少し内部品質やSOLID原則あたりに言及してほしかった
  • 「7.5 出口は1つ」は鵜呑みにしてほしくない。サイクロマティック複雑度を根拠にしているので仕方ないが、関数/メソッドから早期リターンすることはネストを下げて可読性向上につながるので

テスト技法についてのおすすめ資料・書籍

ユニットテストを書く開発者が、テストケースを作るために参考となる「テスト技法」についての資料・書籍を紹介します。

JaSST'21 Tokyoでの河野哲也さんのセッション資料。ユニットテストで使える「同値分割」「デシジョンテーブル」「状態遷移図」が例題とともに紹介されています。

www.slideshare.net

こちらも各テスト技法を解説している書籍です。

各テスト技法の事例・問題集。

所感

書籍などでユニットテストについて紹介するとき、テストケースを作るためのテスト技法は省略されがちです*4。 しかし、開発者もテストを書くならば持つべきスキルだと考えており、その点で本書のように開発者テストとテスト技法を結びつける書籍に期待していました。

本書は残念ながら方向性の異なるものでしたが、「開発者テスト」の概念を知らない方に向けて、薄く広く、俯瞰して理解できる書籍ですので、最初の一冊としてはおすすめできそうです。

*1:内容が悪いという意味ではなく、タイトルがミスリードなのでは感

*2:ISTQB/JSTQBが絶対ということではないのですが

*3:私が「単体テスト」でなく「ユニットテスト」という言葉を使うのは、「単体テスト」が人によって様々なバリエーションを持っているため無用な混乱を避けるためです。この点、本書p.34でも言及されていながら「単体テスト」の語を使っていたりする

*4:自著『iOSアプリテスト自動化入門』では、同値クラス、境界値テスト、デシジョンテーブルについては紹介していましたが

ML-Agentsに入門するならUnity LearnのML-Agents: Penguinsがおすすめ

個人差があるとは思いますが、最初のチュートリアルとして良いサイズだと思うので(そしてUnity Learnの検索で出てこないので)紹介します。

おすすめポイントは、

  • ダウンロードするファイルはペンギン等のfbxのみ
  • コードは説明付きで小分けに提示されていて、コピペするにしても内容を把握しながらできる*1
  • 学習用Python環境のセットアップも解説されている(Anacondaを使用)

なお、Unity Learnは無料で提供されています。

ML-Agents: Penguins

learn.unity.com

このコンテンツ、内容が古いためかUnity Learnの検索で出てきません。 Unity ML-Agents Toolkitは2020年5月に晴れてバージョン1.0がリリースされ、最新版はRelease 12です*2 *3。 一方、このPenguinsチュートリアルはBeta 0.13をベースとしています。

そのため、上記ページそのままではなく、チュートリアルを提供しているImmersive Limit LLCが別に公開しているアップデート情報*4を元に進めます。

www.immersivelimit.com

以下、個人的な補足です。

  • Unity packageはUPM、Python packageはpipで取得できるため、Unity ML-Agents Toolkit リポジトリのclone取得は不要です*5
  • UnityのPackage Managerウィンドウでは ML-Agents 1.0.6 (verified) までしか出ませんが、Packages/manifest.jsonを直接編集すれば 1.7.2-preview も指定できます
  • Anacondaは必須ではありません。ただし何かしらのPythonパッケージ+環境管理ソリューション*6は使ったほうがよさそう
  • Anacondaで環境を作るとき、名前は ml-agents より、Python packageのバージョンを加えて ml-agents-0.23 などとするのがよさそう
  • gitリポジトリで管理するとき、ML-Agentsの生成するファイルは.gitignoreに下記を追加することでトラッキング対象外にできます
Assets/ML-Agents*
results/

自分で学習させたペンギンが動くのはかわいくて、ずっと見てても飽きないですね。

f:id:nowsprinting:20210223225822p:plain

その他のUnity Learnコンテンツについて

Karting Mod:スマートカートのトレーニングガイド

learn.unity.com

日本語対応しているものですが、以下の理由で最初にはおすすめしません。

  • Penguins同様 0.13 ベースで古い(ML-Agentsはプロジェクトに内包しているので動かしてみるだけなら問題はない)
  • Penguinsに比べて要素が多い

ML-Agents: Hummingbirds

learn.unity.com

こちらはバージョン1.0 (Release 1) 時点でのコンテンツです。 動画による前提の説明もあり、「強化学習なんもわからん」人にはこちらから入ってもいいかもしれません。

ただ、説明がほとんど動画で時間もかかるので途中までで止めてしまいました。 続きを進めたらこの記事を更新するつもりです。

参考

Unity ML-Agents Toolkit に入ってるexamplesの解説

ml-agents/Learning-Environment-Examples.md at release_12_docs · Unity-Technologies/ml-agents · GitHub

Unity ML-Agents Toolkit のマイグレーション情報

ml-agents/Migrating.md at main · Unity-Technologies/ml-agents · GitHub

ML Agents 1.0以降に入った変更などの話

https://blogs.unity3d.com/jp/2020/12/28/happy-holidays-from-the-unity-ml-agents-team/blogs.unity3d.com

*1:完成プロジェクトで説明される場合、どこまでML Agentsでどこから自作した機能なのかわからないことが起こりがち

*2:Unity packageとPython packageで別々のバージョンが振られているためこの表現。ちなみにRelease 12のUnity packageは1.7.2、Python packageは0.23.0

*3:これを書いた2日後にRelease 13が出ました

*4:ML-Agents Release 10 向けアップデートとなっていますが、Release 12でもそのまま動きました

*5:多数のExamplesがあるので次のステップとして触ってみるには良いと思います

*6:Minicondaとかvenvとか