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
560
Unityテスト活動のふりかえり
adarapata
1
580
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
Flutter with Dart MCP: All You Need - 박제창 2025 I/O Extended Busan
itsmedreamwalker
0
150
テストカバレッジ100%を10年続けて得られた学びと品質
mottyzzz
2
580
Android 16 × Jetpack Composeで縦書きテキストエディタを作ろう / Vertical Text Editor with Compose on Android 16
cc4966
1
190
RDoc meets YARD
okuramasafumi
4
170
「手軽で便利」に潜む罠。 Popover API を WCAG 2.2の視点で安全に使うには
taitotnk
0
840
実用的なGOCACHEPROG実装をするために / golang.tokyo #40
mazrean
1
260
🔨 小さなビルドシステムを作る
momeemt
4
670
Go言語での実装を通して学ぶLLMファインチューニングの仕組み / fukuokago22-llm-peft
monochromegane
0
120
ソフトウェアテスト徹底指南書の紹介
goyoki
1
150
MCPでVibe Working。そして、結局はContext Eng(略)/ Working with Vibe on MCP And Context Eng
rkaga
5
2.2k
基礎から学ぶ大画面対応(Learning Large-Screen Support from the Ground Up)
tomoya0x00
0
420
もうちょっといいRubyプロファイラを作りたい (2025)
osyoyu
1
410
Featured
See All Featured
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
6k
Reflections from 52 weeks, 52 projects
jeffersonlam
352
21k
4 Signs Your Business is Dying
shpigford
184
22k
The Invisible Side of Design
smashingmag
301
51k
Writing Fast Ruby
sferik
628
62k
Thoughts on Productivity
jonyablonski
70
4.8k
The Pragmatic Product Professional
lauravandoore
36
6.9k
Imperfection Machines: The Place of Print at Facebook
scottboms
268
13k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
How to Ace a Technical Interview
jacobian
279
23k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
51
5.6k
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.7k
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ϕλॻ͖Ͱςετॻ͚·͢ • ςετ͍͢͠ͷɺ͠ʹ͍͘ͷΛׂ͍ͯ͜͠͏ • ͷѲͱ͍͏ࢹͰςετॻ͍ͯΈΔͷ͍͍Α
͓ΘΓ