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.4k
どこから始めるUnity Test
Gotanda Unity #10 のLT資料です。
いも
January 23, 2019
Tweet
Share
More Decks by いも
See All by いも
UnityプログラミングバイブルR6号宣伝&Unity Logging小話
adarapata
0
430
Unityテスト活動のふりかえり
adarapata
1
530
Gather.townはいいぞ その後
adarapata
1
1.5k
Unityでの開発事例
adarapata
3
22k
どこのご家庭にもあるシーンマネージャーの話
adarapata
1
7.6k
Gather.townはいいぞ
adarapata
2
2.3k
宴はいいぞ
adarapata
0
1.3k
わかった気になるモブプログラミング
adarapata
1
98
モブワークっぽいのをやっている話/Trying mobwork
adarapata
2
1.2k
Other Decks in Programming
See All in Programming
富山発の個人開発サービスで日本中の学校の業務を改善した話
krpk1900
4
370
Honoをフロントエンドで使う 3つのやり方
yusukebe
4
2.1k
ファインディの テックブログ爆誕までの軌跡
starfish719
2
1.1k
知られざるDMMデータエンジニアの生態 〜かつてツチノコと呼ばれし者〜
takaha4k
4
1.3k
Kubernetes History Inspector(KHI)を触ってみた
bells17
0
200
AWS Lambda functions with C# 用の Dev Container Template を作ってみた件
mappie_kochi
0
240
第3回関東Kaggler会_AtCoderはKaggleの役に立つ
chettub
3
890
Djangoアプリケーション 運用のリアル 〜問題発生から可視化、最適化への道〜 #pyconshizu
kashewnuts
1
230
『品質』という言葉が嫌いな理由
korimu
0
160
Linux && Docker 研修/Linux && Docker training
forrep
23
4.5k
SRE、開発、QAが協業して挑んだリリースプロセス改革@SRE Kaigi 2025
nealle
3
4.1k
昭和の職場からアジャイルの世界へ
kumagoro95
1
350
Featured
See All Featured
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
27
1.9k
BBQ
matthewcrist
86
9.5k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
193
16k
The Language of Interfaces
destraynor
156
24k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
114
50k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
20
2.4k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
31
2.1k
The Invisible Side of Design
smashingmag
299
50k
Optimizing for Happiness
mojombo
376
70k
GraphQLとの向き合い方2022年版
quramy
44
13k
Fireside Chat
paigeccino
34
3.2k
Adopting Sorbet at Scale
ufuk
74
9.2k
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ϕλॻ͖Ͱςετॻ͚·͢ • ςετ͍͢͠ͷɺ͠ʹ͍͘ͷΛׂ͍ͯ͜͠͏ • ͷѲͱ͍͏ࢹͰςετॻ͍ͯΈΔͷ͍͍Α
͓ΘΓ