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.6k
どこから始めるUnity Test
Gotanda Unity #10 のLT資料です。
いも
January 23, 2019
Tweet
Share
More Decks by いも
See All by いも
UnityプログラミングバイブルR6号宣伝&Unity Logging小話
adarapata
0
580
Unityテスト活動のふりかえり
adarapata
1
590
Gather.townはいいぞ その後
adarapata
1
1.6k
Unityでの開発事例
adarapata
3
23k
どこのご家庭にもあるシーンマネージャーの話
adarapata
1
8.3k
Gather.townはいいぞ
adarapata
2
2.4k
宴はいいぞ
adarapata
0
1.5k
わかった気になるモブプログラミング
adarapata
1
130
モブワークっぽいのをやっている話/Trying mobwork
adarapata
2
1.3k
Other Decks in Programming
See All in Programming
イベントストーミングのはじめかた / Getting Started with Event Storming
nrslib
1
200
OSS開発者の憂鬱
yusukebe
6
2.6k
Nitro v3
kazupon
2
240
Amazon Bedrock Knowledge Bases Hands-on
konny0311
0
140
なぜ強調表示できず ** が表示されるのか — Perlで始まったMarkdownの歴史と日本語文書における課題
kwahiro
8
4.8k
Core MIDI を勉強して作曲用の電子ピアノ作ってみた!
hypebeans
0
100
知られているようで知られていない JavaScriptの仕様 4選
syumai
0
390
2026年向け会社紹介資料
misu
0
150
オフライン対応!Flutterアプリに全文検索エンジンを実装する @FlutterKaigi2025
itsmedreamwalker
1
140
高単価案件で働くための心構え
nullnull
0
100
競馬で学ぶ機械学習の基本と実践 / Machine Learning with Horse Racing
shoheimitani
0
260
CloudflareのSandbox SDKを試してみた
syumai
0
130
Featured
See All Featured
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.1k
GitHub's CSS Performance
jonrohan
1032
470k
Embracing the Ebb and Flow
colly
88
4.9k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1k
We Have a Design System, Now What?
morganepeng
54
7.9k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
51k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.3k
Building Adaptive Systems
keathley
44
2.8k
Statistics for Hackers
jakevdp
799
220k
Large-scale JavaScript Application Architecture
addyosmani
514
110k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
46
7.8k
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ϕλॻ͖Ͱςετॻ͚·͢ • ςετ͍͢͠ͷɺ͠ʹ͍͘ͷΛׂ͍ͯ͜͠͏ • ͷѲͱ͍͏ࢹͰςετॻ͍ͯΈΔͷ͍͍Α
͓ΘΓ