Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Unityテスト活動のふりかえり
Search
いも
December 12, 2021
Programming
690
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Unityテスト活動のふりかえり
【年末だよ】Unity お・と・なのLT大会 2021
https://meetup.unity3d.jp/jp/events/1337
いも
December 12, 2021
More Decks by いも
See All by いも
UnityプログラミングバイブルR6号宣伝&Unity Logging小話
adarapata
0
640
Gather.townはいいぞ その後
adarapata
1
1.7k
Unityでの開発事例
adarapata
3
23k
どこのご家庭にもあるシーンマネージャーの話
adarapata
2
8.8k
Gather.townはいいぞ
adarapata
2
2.4k
宴はいいぞ
adarapata
0
2.2k
わかった気になるモブプログラミング
adarapata
1
180
モブワークっぽいのをやっている話/Trying mobwork
adarapata
2
1.3k
Zenjectを導入する前に
adarapata
0
4.1k
Other Decks in Programming
See All in Programming
the container ship “Apple Silicon”@WWDC26 Recap -Japan-\(region).swift
shingangan
0
130
琵琶湖の水は止められてもNet--HTTPのリトライは止められない / You might be able to stop the water flow of Lake Biwa but you can't stop Net::HTTP retries
luccafort
PRO
0
760
Detecting Compromised CI with eBPF and Cilium Tetragon
lizrice
0
210
komatsuna「分散システムにおけるバグ分析手法」
komatsunaqa
0
260
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
340
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
1
990
プロポーザルを書いてもらう
pvcresin
0
550
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
310
<title><a id="</title>君はこのHTMLをパースできるか"></a></title> #雑LT_study
pizzacat83
0
150
関東Kaggler会_NVIDIA_Nemotron_コンペ_振り返り
rick_ds
0
640
今さら聞けない .NET CLI
htkym
0
200
2年かけて Deno に DOMMatrix を実装した話 / How I implemented DOMMatrix in Deno over two years
petamoriken
0
210
Featured
See All Featured
AI: The stuff that nobody shows you
jnunemaker
PRO
9
920
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.3k
Building an army of robots
kneath
306
46k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.3k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.5k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Discover your Explorer Soul
emna__ayadi
2
1.3k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Paper Plane (Part 1)
katiecoart
PRO
1
10k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
270
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
Transcript
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Unityテスト活動のふりかえり いも @adarapata 2021/12/12【年末だよ】Unity お・と・なのLT大会 2021 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1
自己紹介 いもです @adarapata 仕事でゲームとか作ってる DIとかテストが好きです 御朱印巡りはじめました https://adarapata.com 2
Unityテスト活動のふりかえり 公私で行ってきたUnityでのテスト関連について雑にふりかえる 実践編 自身がテストを書いていく上で意識しながら行ったことの話 啓蒙編 他者にテストを書いてもらう上で意識しながら行ったことの話 3
実践編 今回は以下の例での話をします スマートフォンゲーム開発 複数人で開発している 数年運用する想定である 一般的にアウトゲームと呼ばれる部分を中心とする E2Eの話はしません 4
面倒なところを先回りする 後々テスト書くときに面倒になりそうだな~という部分を先に対応す る シングルトンの撤廃 テスト領域を明確にする 通信は手厚くする データを用意しやすくする 5
シングルトンの撤廃 みんな大好きシングルトン staticなインスタンスは交換しにくい MonoBehaviourのシングルトンはシングルトンじゃない説 大体テスト書こうとしたときにシングルトンは障害となりやすいの で、最初から利用しない方針にする。 6
対応例 そもそもシングルトンインスタンスを作らなくていいような仕組み が必要 DIできたら基本的に必要なくなりそう VContainerを導入 https://vcontainer.hadashikick.jp 今回欲しいのはDIコンテナのみなのでVContainerは丁度よい 7
テスト領域を明確にする 全部書くのは大変で旨味が少ない MonoBehaviourが絡むとテストしにくい できないことはない プロダクトがカバーしたい範囲はどこなのかを洗い出す 8
対応例 今回は画面に対してModel-View-Presenter(MVP)構造 Presenter-Viewは書かない ViewはMonoBehaviourとして持っているので書くのが大変 PresenterはViewを直接持つので実質MonoBehaviourへの依存 上記は伝搬と出力くらいのコードにしましょう それ以外のクラスは書けるようにしていきましょう 方針を定めることで、テストできる領域にコードを寄せていく。 refs 「HumbleObjectPatternな話」
https://speakerdeck.com/adarapata/humble-object-patternnahua 9
通信を手厚くする アウトゲームの中枢に入ってくるやつ 外部との通信が入るとテスト難易度は高い テストを書かなかったとしても、開発中の通信偽装は欲しい サーバーができていないくても進めれる仕組みは欲しい この辺は実装前からオブジェクトを差し替えられる前提で作っておい たほうが楽 10
対応 通信クラスを抽象化してモックできるようにする モック用通信クラスを作る 一例 https://speakerdeck.com/adarapata/unityyong- mockclientfalsehua レスポンスを外部から流し込める機能があればとりあえずOK UnitTest用に使ってたが、アプリケーション側でそのまま使えそうだ ったので転用できた。 11
データを用意しやすくする テスト対象が依存しているデータをサクッと準備したい 読み込み方、更新方法が特殊だととてもテストしにくい 必ずサーバーから取るとか 巨大なDataManagerを持つと更に辛い Characterデータだけ欲しいのにShopデータを用意するのは嫌 ゲームで都度外部IOは体験が悪いので基本はオンメモリにしたい 上記の理由から、シンプルに1つの種類のデータを保持するクラスだ けあれば嬉しそう。 12
対応例 データの取得・更新はRepositoryを用意するという方針を取った public interface IUserCharacterRepository { void Update(List<UserCharacter> characters); UserCharacter
Get(UserCharacterId id); } public interface IMasterCharacterRepository { MasterCharacter Get(MasterCharacterId id); } 13
外からの流し込みをしやすくするために保存・取得以外行わない 1つのRepositoryは極力1データクラスのみ取り扱う Repositoryは他のRepositoryを見ない ここを許容すると循環参照生まれがち 複数のRepositoryを取り扱いたいなら素直に上位のクラスを作る public class CharacterFinder { private
readonly IUserCharacterRepository _userRepository; private readonly IMasterCharacterRepository _masterRepository; public (MasterCharacter, UserCharacter) FindCharacter(UserCharacterId id) {} } 14
データ生成はテスト用のFactoryメソッドを用意してあげる public class TestUtility { public static UserCharacter CreateCharacter(int id
= 1, int masterId = 100) {} } ScriptableObjectなどの外部データ化もあり 15
リファクタし続ける テストはコード品質を上げない リファクタにこそ価値がある 開発中の「本当はこうした方がよい」は山ほどある 大体後からやるとつらい 時には影響範囲の大きいドラスティックな改修もやる必要がある。 その際にテストコードを指標にしてやるべきことを定める 16
体験例:通信の基盤の改善 通信クラスのレスポンスの構造を変えたいが、既にかなり利用されて いるので多くの箇所に影響してしまう。 以下の手順で改修した 1. おもむろに実装を変える 2. テストが大量に落ちる(ここで影響範囲がある程度見える) 3. 全て
[Ignore] を書いてスキップさせる 4. 1個ずつ直してPR出していく ゴールが見えるようになることで、見積もりの精度と勇気をもらう 17
テストもリファクタし続ける テストコードもコードでありリファクタの対象 毎回書いてるコードは纏めていく テストを書くことを億劫にさせない 不要となったテストケースは削除していく 仕様が変わったけどなんとなく生きてるやつとか 頻繁に落ちて直してるケースなど 18
良かった所 基本的にはテストを書けるという環境を用意できた 大きな変更に対して強い意志を持ててる 改善できそうな所 未だにMonoBehaviourのテストの答えが出ない ユニットテストを書きたかったらUnityが提供するコンポーネント から距離を置くという判断になったが、それが適切であるか Prefabに対してのテストという観点を設けていいかもしれない Addressable使ってるなら読み込みは楽だしいけるかも 19
啓蒙編 プライベートで他の人がUnityでテストを書けるようになるための活 動を行っていました テストコードとTDDの座学 TDDリポジトリを使ったハンズオン ペアプロ・モブプロでのTDD 20
なぜやってるのか(抜粋) https://adarapata.hatenablog.com/entry/2021/09/15/233534 ゲーム開発はソフトウェア開発の中でもかなり複雑性が高いと感 じています。そして性質上変更頻度も高い。ゲームごとに作り方 が変わる以上これは仕方ないことだと考えています。だからこそ より変化に対応できるようにテスタビリティの高いコードになっ ていてほしいと考えていますがその難易度、そしてそもそものテ ストコード文化というものがないためにテストコードが書かれて いることは少ないです。 まずはUnity界隈でテストコードを書
く、という文化を作っていきたい。そんな気持ちで活動を行って います。 “ “ 21
TDDリポジトリを使ったハンズオン https://github.com/adarapata/UnityTDD_Example ハンズオン用に作ったRepo サンプルは業務で実体験したものを抽象化したもの Unityゲーム開発者ギルド(UGDG)や副業などで使いました ご自由にお使いください 22
ペアプロ・モブプロでのTDD 前述のハンズオンをモブプロしたり 特定の業務コードに対してペア・モブしたり 狙いとしては、テストに対して個人ではなくチームで関心を持って もらうこと どうテストを書いたらいいかを話し合える土壌づくり https://speakerdeck.com/adarapata/wakatutaqi- ninarumobupuroguramingu 23
活動の所感 テストを書く際に次のような課題が発生するケースが多かった 即物的な誘惑 レガシーに対しての踏み出し方 24
即物的な誘惑 1+1=2のテストを書いても仕方がない 即役に立つようなテストを書きたい 外部品質に直結する粒度で書きたくなる こうなるとテストの粒度が大きくなり、難易度も上がってしまう。 25
対策 バグを減らすという直接的な目的に囚われがち ユニットテスト ≠ バグを減らすではないことの徹底 アジャイルテスト4象限のお話 26
レガシーに対しての踏み出し方 すでにリリースされたタイトルでテストコードを書き始めるのは大変 往々にしてテスタビリティが低い 開発を止めることはできない ガッツリテストコードを書く時間を用意しにくい リファクタリングも同様 日々の開発に少しずつテストを書くという習慣をつけていく必要があ る 27
学習のためのテスト戦略 なにはともあれ書けそうなものを探してみる。 staticメソッドのテスト staticメソッドは状態を持たない AのときにBであるというシンプルなテストを書きやすい ここから初めてテストを書くという感覚を身に付けていく ただしシングルトンは除く 28
学習のためのテスト戦略 書けない!と思ったときに問題を分析していく 何をテストしていいのかわからないから 目の前のクラスの役割は理解できているか? テストするための依存オブジェクトが準備できないから クラスが責務を負いすぎていないか? テストの記法がわからないから みんなでNUnitのページ見ましょう 29
大きなコードとの向き合い方 例:「HP10%以下で強力な攻撃を放つ敵」という巨大なクラスの場合 public class BigEnemy { public void Update() {
/* すごく長い処理がいっぱい */ if(life / maxLife < 0.1F){ StrongAttack(); // 攻撃ダメージ計算とか演出とか } } } 30
全てを解決しようとすると難しい HP10%以下になったらちゃんと動く? 攻撃処理は想定通り動く? そもそもEnemyは単体で動くの? 様々な問題と向き合うことになり、頭が痛くなる・・。 31
問題の分割統治 「HPがn%以下になったことを検知できる機能」にフォーカスを当 てることはできる そこだけクラスを切り出し、テストを書く 動作を保証できたら該当箇所を差し替える 大きなコードを小さな機能に分解していき各個撃破で問題を潰してい く 32
良かった所 少なからずTDDへの興味・理解を示す人がいた ライブラリを理解するためにテスト書いたり まったくわからない状態から「書いてみる」に進められた 改善できそうな所 テストコードの書き方とTDDを同時に教えていた テストコード自体も初めての人が多かったので 場合によっては初モブプロも同時に教えることになった 学習難易度が上がり、全員が理解できたとは言えない状況だった。 33
最後に テストはゲームを面白くしないが、もっと面白くできると思ったとき に実現するための支えとなる。 34
引用 P27. Agile Testing Quadrants https://www.informit.com/articles/article.aspx? p=2253544&ranMID=24808 35