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 Test
Search
いも
January 23, 2019
Programming
5
3.5k
どこから始めるUnity Test
Gotanda Unity #10 のLT資料です。
いも
January 23, 2019
Tweet
Share
More Decks by いも
See All by いも
UnityプログラミングバイブルR6号宣伝&Unity Logging小話
adarapata
0
550
Unityテスト活動のふりかえり
adarapata
1
570
Gather.townはいいぞ その後
adarapata
1
1.6k
Unityでの開発事例
adarapata
3
22k
どこのご家庭にもあるシーンマネージャーの話
adarapata
1
8.1k
Gather.townはいいぞ
adarapata
2
2.4k
宴はいいぞ
adarapata
0
1.5k
わかった気になるモブプログラミング
adarapata
1
120
モブワークっぽいのをやっている話/Trying mobwork
adarapata
2
1.3k
Other Decks in Programming
See All in Programming
AI時代のドメイン駆動設計-DDD実践におけるAI活用のあり方 / ddd-in-ai-era
minodriven
23
9k
CEDEC2025 長期運営ゲームをあと10年続けるための0から始める自動テスト ~4000項目を50%自動化し、月1→毎日実行にした3年間~
akatsukigames_tech
0
150
Honoアップデート 2025年夏
yusukebe
1
850
Terraform やるなら公式スタイルガイドを読もう 〜重要項目 10選〜
hiyanger
13
3.2k
「リーダーは意思決定する人」って本当?~ 学びを現場で活かす、リーダー4ヶ月目の試行錯誤 ~
marina1017
0
240
サーバーサイドのビルド時間87倍高速化
plaidtech
PRO
0
490
【第4回】関東Kaggler会「Kaggleは執筆に役立つ」
mipypf
0
790
TanStack DB ~状態管理の新しい考え方~
bmthd
2
330
CSC305 Summer Lecture 05
javiergs
PRO
0
110
LLMOpsのパフォーマンスを支える技術と現場で実践した改善
po3rin
8
980
Flutterと Vibe Coding で個人開発!
hyshu
1
270
Scale out your Claude Code ~自社専用Agentで10xする開発プロセス~
yukukotani
9
2.6k
Featured
See All Featured
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
15
1.6k
The Cult of Friendly URLs
andyhume
79
6.5k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
31
2.2k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
7
820
Large-scale JavaScript Application Architecture
addyosmani
512
110k
Why You Should Never Use an ORM
jnunemaker
PRO
59
9.5k
The World Runs on Bad Software
bkeepers
PRO
70
11k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
Why Our Code Smells
bkeepers
PRO
338
57k
What's in a price? How to price your products and services
michaelherold
246
12k
The Language of Interfaces
destraynor
160
25k
Transcript
Ͳ͔͜Β࢝ΊΔ Unity Test 2019/1/23 Gotanda Unity #10
͍Ͱ͢ • ͍(@adarapata) • https://adarapata.com • ϛΫγΟ XFLAG UnityΤϯδχΞ •
εϚϒϥੈքઓಆྗ53ສ
ࠓ͢͜ͱ • UnityͰ۩ମతʹͲ͏͍͏෩ʹςετॻ͖ਐΊ͍ͯͬͨΒ ͍͍ͷʁͱ͍͏ • ͏ͪͷήʔϜʹࠓ͔ΒೖΕΔͷͳ͊ɾɾΈ͍ͨʹ᪳ͬ ͍ͯΔਓΛޙԡ͢͠Δ • ςετ͋·Γॻ͍ͨ͜ͱͳ͍ਓ͚
ͳͥςετΛॻ͘ͷ͔ • ࣭ͷѲ/ਫ਼ਆతোนͷഉআ • աڈʹهࣄΛॻ͍ͨͷͰࢀর͍ͩ͘͞ɻ • ʮςετίʔυʹ͍ͭͯͷจॻΛॻ͍͍ͯͨʯhttp:// adarapata.hatenablog.com/entry/2018/08/16/001607
UnityͰΑ͋͘Δίʔυʹରͯ͠ ϢχοτςετΛॻ͍ͯΈΔ • MonoBehaviorʹ৭ʑॻ͍ͯΔͭ • αϯϓϧͰ͋Γͦ͏ͳSTGͷࣗػ • খنͳϓϩμΫτ ݁Λઌʹݴ͏ͱઈ͠ΜͲ͍
public class PlayerUnit : MonoBehaviour { [SerializeField] private Bullet _bulletPrefab
= null; [SerializeField] private float _interval; [SerializeField] private float _speed; [SerializeField] private int _hp; private float _reloadTime; void Update() { float horizontal = Input.GetAxis("Horizontal"); float vertical = Input.GetAxis("Vertical"); transform.position += new Vector3(horizontal, vertical, 0F) * _speed * Time.deltaTime; if (Input.GetButton("Fire1") && _reloadTime < 0) { var bullet = Instantiate(_bulletPrefab, transform.position, Quaternion.identity); bullet.SetUp(Vector2.up); _reloadTime = _interval; } _reloadTime -= Time.deltaTime; } void OnTriggerEnter2D(Collider2D collider) { if (collider.tag == "Bullet") { _hp--; if (_hp <= 0) { Destroy(gameObject); } } } }
͍ͬͯͧ͘
PlayerUnitʹͬͯ΄͍͜͠ͱ Λࢥ͍ग़͢ • Ҡಈ͢Δ • Λൃࣹ͢Δ • μϝʔδΛड͚Δ
PlayerUnitʹͬͯ΄͍͜͠ͱ Λࢥ͍ग़͢ • Ҡಈ͢Δ // ࠓ͚ͩ͜͜ • Λൃࣹ͢Δ • μϝʔδΛड͚Δ
Ҡಈͷςετ • ೖྗ͕͋Δͱɺಈ͍ͯཉ͍͠ • ಈ͘ = transform.positionʹมԽ͕͋Δ
namespace Tests { public class PlayerUnitTest { [UnityTest] public IEnumrator
MoveTest() { var gameObject = new GameObject(); var playerUnit = gameObject.AddComponent<PlayerUnit>(); var beforePosition = playerUnit.transform.position; yield return null; Assert.AreNotEqual(beforePosition, playerUnit.transform.position); } } } ͜Μͳײ͡ʹॻ͚Δͱ͍͍ͳ
μϝͰ͢ • Position͕ಉҰ = ಈ͍͍ͯͳ͍ • άϦʔϯࢦͯ͠ؤுΔͧ
௨Βͳ͍ཧ༝Λߟ͑Δ public class PlayerUnit : MonoBehaviour { [SerializeField] private Bullet
_bulletPrefab = null; [SerializeField] private float _interval; [SerializeField] private float _speed; [SerializeField] private int _hp; private float _reloadTime; void Update() { float horizontal = Input.GetAxis("Horizontal"); float vertical = Input.GetAxis("Vertical"); transform.position += new Vector3(horizontal, vertical, 0F) * _speed * Time.deltaTime; ~~~~ } } • _speedʹ͕ೖͬͯͳ͍ • ΩʔೖྗͰ͖ͯͳ͍ͷͰ࣮࣭0ϕΫτϧ SerializeFieldInputTest͔Βѻ͑ͳ͍
ςετ͍͢͠ͷͱ͠ʹ͍͘ͷΛ͢Δ • Unity APIʹґଘ͍ͯ͠ͳ͍Ϋϥε • Unity APIʹґଘ͍ͯ͠ΔΫϥε • RigidBody,Animator etc..
• MonoBehaviourΛܧঝͨ͠Ϋϥε • GUI෦ Unityଆʹۙͮ͘ʹͭΕͯςετͷқ্͕͍ͬͯ͘ ςετ͍͢͠ͷ ςετ͠ʹ͍͘ͷ
ςετ͍͢͠ํʹدͤΔ public class PlayerUnit : MonoBehaviour { [SerializeField] private Bullet
_bulletPrefab = null; [SerializeField] private float _interval; [SerializeField] private float _speed; [SerializeField] private int _hp; private float _reloadTime; void Update() { float horizontal = Input.GetAxis("Horizontal"); float vertical = Input.GetAxis("Vertical"); transform.position += new Vector3(horizontal, vertical, 0F) * _speed * Time.deltaTime; ~~~~ } } • ܭࢉॲཧ͚ͩΓग़ͤςετॻ͚ͦ͏ • Inputʹґଘ͠ͳ͚Εςετ࣌ͷೖྗΛ༻ҙͰ͖ͦ͏ ॻ͖ͮΒ͍ͱ͜Ζॻ͔ͳ͍
public class PlayerUnitMove { private float _speed; public PlayerUnitMove(float speed)
{ _speed = speed; } public Vector3 CalculateVelocity(Vector3 direction) => direction.normalized * _speed; } namespace Tests { public class PlayerUnitMoveTest { [Test] public void CalculateVelocityTest() { var move = new PlayerUnitMove(3); Assert.AreEqual(new Vector3(0, 3F,0), move.CalculateVelocity(Vector3.up)); } } } ܭࢉॲཧ͚ͩΫϥεΛΓग़͢
public class PlayerUnit : MonoBehaviour { [SerializeField] private Bullet _bulletPrefab
= null; [SerializeField] private float _interval; [SerializeField] private int _hp; private float _reloadTime; private PlayerUnitMove _move; public void Initialize(PlayerUnitMove move) { _move = move; } void Update() { float horizontal = Input.GetAxis("Horizontal"); float vertical = Input.GetAxis("Vertical"); var direction = new Vector3(horizontal, vertical, 0F); transform.position += move.CalculateVelocity(direction) * Time.deltaTime; ~~~~ } } Ҡಈܭࢉ෦Λࠩ͠ସ͑ ΦϒδΣΫτ֎෦͔ΒͤΔΑ͏ʹ͢Δ
InputґଘΛΊΔ public interface IPlayerUnitInput { Vector3 GetAxis(); } public class
IUnityInput : IPlayerUnitInput { public Vector3 GetAxis() { float horizontal = Input.GetAxis("Horizontal"); float vertical = Input.GetAxis("Vertical"); return new Vector3(horizontal, vertical, 0); } } ೖྗ෦ΛΠϯλϑΣʔεʹͯ͠ɺPlayerUnitʹΩʔೖྗΛҙࣝͤ͞ͳ͍
InputґଘΛΊΔ ·ͨΦϒδΣΫτ֎෦͔ΒͤΔΑ͏ʹ͢Δ public class PlayerUnit : MonoBehaviour { [SerializeField] private
Bullet _bulletPrefab = null; [SerializeField] private float _interval; [SerializeField] private int _hp; private float _reloadTime; private PlayerUnitMove _move; private IPlayerUnitInput _input; public void Initialize(PlayerUnitMove move, IPlayerUnitInput input) { _move = move; _input = input; } void Update() { var direction = _input.GetAxis(); transform.position += move.CalculateVelocity(direction) * Time.deltaTime; ~~~~ } }
namespace Tests { public class PlayerUnitTest { class MockInput :
IPlayerUnitInput { private Vector3 _axis; public MockInput(Vector3 axis) { _axis = axis; } public Vector3 GetAxis() => _axis; } [UnityTest] public IEnumerator MoveTest() { var gameObject = new GameObject(); var playerUnit = gameObject.AddComponent<PlayerUnit>(); var mockInput = new MockInput(Vector3.up); playerUnit.Initialize(new PlayerUnitMove(1), mockInput); var beforePosition = playerUnit.transform.position; yield return null; Assert.AreNotEqual(beforePosition, playerUnit.transform.position); } } } ͪΐͬͱॻ͖ͯ͠ςετ࣮ߦ
✔
ςετͱ͍͏͔ ϦϑΝΫλϦϯά͡Όͳ͍ʁ
͍
MonoBehaviorͷςετ͠ΜͲ͍ • MonoBehaviorϕλॻ͖ςετ͠ʹ͍͘ • ϏδωεϩδοΫΛMonoBehaviorʹॻ͍͍ͯ͘ͱҾͬு ΒΕͯςετқ্͕͕Δ • ͭ·Γີ݁߹ • ີ݁߹Α͍ઃܭͱݴ͑ͳ͍
• ςετͷ͠ʹ͔͘͞ΒઃܭͷΛѲ͢Δ
Humble Object ύλʔϯ • ςετ͠ʹ͍͘ͷͱͦ͏Ͱͳ͍ ͷΛ໌֬ʹׂ͚ͯ͢Δύλ ʔϯ • GUIͷॲཧͷৄࡉςετ͠ʹ͍͘ ͕ɺGUIͷৼΔ͍ςετͰ͖Δ
• ӈͷίʔυɺͷੜ෦ͷς ετ͍͕͠ɺʮੜ͢Δͱ͍ ͏ৼΔ͍͕ߦΘΕ͔ͨʯ·Ͱ ςετͰ͖Δ • MonoBehaviorʹ༗ޮ͔͠Εͳ ͍ public class PlayerUnitPresenter { private IPlayerUnitView _view; public void Shot(Vector3 position) { _view.Shot(position); } } public interface IPlayerUnitView { void Shot(Vector3 position); } public class PlayerUnitView : MonoBehaviour, IPlayerUnitView { public void Shot(Vector3 position) { // ࡞ͬͨΓ͢Δ } }
ςετίʔυͷՁ • ಈ࡞֬ೝͱ͍͏ࢹ͚ͩͳΒɺҰճॻ͍ͯऴΘΓͷݸਓ ϓϩμΫτʹೖΕΔҙٛബ͍ • ࢹˍΤσΟλ࠶ੜͷ͕͍έʔεଟ͍ • લड़ͷ௨Γઃܭͷͷؾ͖ͮΛಘΒΕΔࣄଟ͍ • ؾ͖ͮະདྷͷ։ൃ࣌ؒॖ
ؾ͖ͮͷΉ͔͠ͳ͠ • UserData(Ծ໊)ͱ͍͏Ϣʔβͷ͋ΒΏΔσʔλΛอ࣋ͨ͠Γ ॲཧͰ͖Δେ͖ͳΫϥε͕͋ͬͨ • ͋·Γྑ͘ͳ͍ΑͶͱ͍͏ೝࣝͰ্ָ͕࣮͋ͬͨͳͷ Ͱͦͷ··ͩͬͨ • ςετॻ͖࢝Ίͨஈ֊ͰUserData͕བྷΉςετқ͕ߴ ͍͜ͱʹؾ͖ͮ࢝Ίͨ
• νʔϜͰʹͳΓɺUserDataͷϦϑΝΫλϦϯά͕༏ઌత ʹߦΘΕ·ͨ͠ͱ͞
·ͱΊ • MonoBehaviorϕλॻ͖Ͱςετॻ͚·͢ • ςετ͍͢͠ͷɺ͠ʹ͍͘ͷΛׂ͍ͯ͜͠͏ • ͷѲͱ͍͏ࢹͰςετॻ͍ͯΈΔͷ͍͍Α
͓ΘΓ