Hikayeler

Reklam vermek için turkmmo@gmail.com

Unity Test - Framework Giriş (Eğitim) | Mobil Oyun Geliştirme

sergioneral

enjoy the silence 👌
Telefon Numarası Onaylanmış Üye TC Kimlik Numarası Doğrulanmış Üye
Fahri Üye
Katılım
17 Haz 2010
Konular
3,640
Mesajlar
19,614
Online süresi
17g 50672s
Reaksiyon Skoru
4,815
Altın Konu
163
Başarım Puanı
474
Yaş
31
TM Yaşı
15 Yıl 10 Ay 10 Gün
MmoLira
-933
DevLira
0

Metin2 EP, Valorant VP dahil tüm oyun ürünlerini en uygun fiyatlarla bulabilir, Item ve Karakterlerinizi hızlıca satabilirsiniz. HEMEN TIKLA!

4747872021_cd8c1ee91b_b-2-2xl.jpg

Merhaba değerli Turkmmo takipçileri... Test, oyun geliştirmenin önemli bir parçasıdır. Manuel test genellikle bariz yoldur. Ancak manuel testler çok tekrarlayıcı olabilir. Bu nedenle test otomasyonu, herhangi bir oyun geliştirme ekibi için çok güçlü bir araçtır.

Kendinize “birlikte testler nasıl yazılır?” diye soruyorsanız, bu eğitim tam size göre.
  • Unity Test Framework nasıl kurulur
  • NUnit ile ilk testinizi nasıl yazabilirsiniz?
  • Unity InputSystem ile girişler nasıl simüle edilir
Örnek Proje

Bu eğitim için kullanacağız. Kod > Zip İndir'e tıklayarak projeyi indirin.

2021-03-04_20-40-md.png

Unity ile projeyi açın. Scenes/Main.unity sahnesini açın.

Sahneyi başlatın ve oyun mekaniği hakkında fikir sahibi olmak için oyunu oynayın. Oyun, iskeletlerin sizi kovaladığı basit bir aksiyon oyunudur. Kılıcınızı (sol tıklama), telekinezi gücünüzü (sağ tıklama) veya şok dalgası gücünüzü (orta düğmeyi basılı tutun ve bırakın) kullanarak onları öldürebilirsiniz.



r tuşuna basarak oyunu sıfırlayabilirsiniz.

Unity Test Framework yükleme

Unity Test Framework (UTF), Unity tarafından sağlanan bir pakettir. Paket yöneticisi aracılığıyla kullanılabilir.

Paketi kurmak için Pencere > Paket Yöneticisi'ne gidin. Arama çubuğu aracılığıyla Test Çerçevesini arayın ve en son sürümü (bu öğreticiyi yazarken 1.1.22) yükleyin.

2021-03-04_00-00-2-md.png


2021-03-04_00-06-md.png

Test Montajını Ayarlama

Çerçeveyi yüklemek, Pencere > Genel > Test Çalıştırıcısı altındaki yeni bir panele erişmenizi sağlar:

2021-03-04_14-24-3-md.png


2021-03-04_14-29-md.png

Koşucunun PlayMode ve EditMode olmak üzere 2 ana sekmesi vardır. PlayMode, PlayMode'dayken çalışacak testler içindir (oyunu gerçek zamanlı oynuyormuşsunuz gibi). EditMode testleri Unity Editor'da çalışır ve oyun kodunun yanı sıra Editör koduna da erişebilir. Bu nedenle Editör uzantıları için daha uygundur.

Son oyun yapısına mümkün olduğunca yakın testler yazmak istiyorsunuz. Yani PlayMode muhtemelen istediğiniz gibi olacaktır.

PlayMode testleri yazmaya başlamak için Varlıklar Klasörünüze gidin ve ardından koşucuda PlayMode Test Montaj Klasörü Oluştur'a tıklayın. Bu, varsayılan olarak Testler adlı yeni bir Klasör oluşturmalıdır.

2021-03-04_14-40-md.png

Klasörün içinde, testleriniz için derleme tanımı olan Tests.asmdef'i bulacaksınız. Testlerinizin oyun koduna erişmesi gerekecek. Bunu başarmak için kodun geri kalanı için başka bir derleme oluşturuyoruz ve ardından bunu Tests.asmdef'e bağlıyoruz.

Varlıklar klasörünüze gidin ve bağlamsal menü Oluştur > Montaj Tanımı ile. Dosyaya bir ad verin (örneğin GameAssembly).

2021-03-04_14-44-md.png

Bu, tüm oyun kodunu yeni derleme ile ilişkilendirecektir. Kod, InputSystem'e bağlıdır, bu nedenle yeni derlemede ona başvurmanız gerekir. Denetçide GameAssembly.asmdef'i açın ve referanslara Unity.InputSystem ekleyin. Değişiklikleri uygulayın:

2021-03-04_14-52-md.png

Şimdi Testler derlemenize geri dönün. Denetçide, Montaj Tanımı Referanslarına GameAssembly'ı ekleyin. Değişikliği kaydetmeyi unutmayın.

2021-03-04_14-57-md.png

Farklı test türleri hakkında bir not

Oyununuz için herhangi bir test yazmaya başlamadan önce kendinize ne tür testler istediğinizi sormalısınız. UTF yalnızca bir çerçevedir ve yalnızca kodla testler yazmak için araçlar sağlar. Yazacağınız testler bu nedenle size kalmış.

Teste aşina değilseniz, Birim Testi ile başlayabilirsiniz. Ancak daha birçok test türü vardır. Entegrasyon testleri ve performans testleri örneğin birkaçıdır.

İlk testiniz

Son olarak, ilk testi yazmaya başlayabiliriz. Bunu yapmak için Test Runner aracılığıyla bir test komut dosyası oluşturacağız.

Testler klasörünüze gidin ve Testler montaj tanımını seçin. Koşucuda, geçerli klasörde Test Komut Dosyası Oluştur'a tıklayın. TestSuite olarak adlandırın ve dosyayı açın. İçerik şöyle görünmelidir:

C#:
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;

namespace Tests
{
    public class TestSuite
    {
        // A Test behaves as an ordinary method
        [Test]
        public void TestSuiteSimplePasses()
        {
            // Use the Assert class to test conditions
        }

        // A UnityTest behaves like a coroutine in Play Mode.
        // In Edit Mode you can use `yield return null;` to skip a frame.
        [UnityTest]
        public IEnumerator TestSuiteWithEnumeratorPasses()
        {
            // Use the Assert class to test conditions.
            // Use yield to skip a frame.
            yield return null;
        }
    }
}

Bir oyuncunun doğru miktarda HP'ye sahip olup olmadığını ve ApplyDamage yöntemini kullanmanın bunu değiştirip değiştirmediğini test edeceğiz.

Player prefabrike referans vermek için sınıfa bir üye ekleyin:

C#:
public class TestSuite
{
    GameObject playerPrefab = Resources.Load<GameObject>("Player");

    ...
}

İlk testi TestPlayerDamage olarak yeniden adlandırın ve bir oyuncu örneği oluşturun:

C#:
[Test]
public void TestPlayerDamage()
{
    Vector3 playerPos = Vector3.zero;
    Quaternion playerDir = Quaternion.identity; // the default direction the player is facing is enough
    GameObject player = GameObject.Instantiate(playerPrefab, playerPos, playerDir);
}

Test şimdi Test Runner'da görünecektir. Testin kendisi henüz kullanışlı olmasa bile, zaten çalıştırabilirsiniz. Koşucuda, ağaçtaki testi seçin ve Seçilenleri Çalıştır'a tıklayın.

2021-03-04_15-07-md.png

Test hiçbir şeyi kontrol etmediği için geçer. Oyuncunun 100 HP'ye sahip olup olmadığını kontrol etmek için bir iddia ekleyin:

C#:
Assert.That(player.GetComponent<Player>().health, Is.EqualTo(100f));

Bu testi çalıştırın ve başarısız olduğunu görün. Bunun nedeni, oynatıcı prefabrik için varsayılan HP'nin 100 değil 99 olmasıdır.

Player/Resources/Player.prefab öğesini seçin ve denetçi aracılığıyla Sağlığını 100 olarak değiştirin. Testi tekrar çalıştırın ve bu sefer yeşile döner.

Şimdi, oyuncuda ApplyDamage yöntemini kullanmanın HP'sini değiştirdiğinden emin olmak istiyoruz. Bunu yapmak için oynatıcıdaki yöntemi çağırın ve başka bir iddia ekleyin. Tam test şimdi şöyle görünüyor:

C#:
[Test]
public void TestPlayerDamage()
{
    Vector3 playerPos = Vector3.zero;
    Quaternion playerDir = Quaternion.identity; // the default direction the player is facing is enough
    GameObject player = GameObject.Instantiate(playerPrefab, playerPos, playerDir);

    Assert.That(player.GetComponent<Player>().health, Is.EqualTo(100f));

    player.GetComponent<Player>().applyDamage(20f);
   
    Assert.That(player.GetComponent<Player>().health, Is.EqualTo(80f));
}

Testi tekrar çalıştırın ve bu sefer yeni iddia ile geçer. Bu, applicationDamage yönteminin oynatıcı HP'sini beklendiği gibi değiştirdiği anlamına gelir.

Tebrikler! İlk Unity testinizi yazdınız.

Daha iyi bir test: İskelete saldırmak

Önceki test oyunun çok küçük bir bölümünü test ettiği için pek kullanışlı değil. Daha faydalı bir şey için, iskelete saldırmanın HP'sini etkileyip etkilemediğini kontrol edeceğiz.

Bu test aşağıdaki gereksinimlere sahiptir:
  • Oyuncu ve iskelet prefabriklerine erişim​
  • Oyun döngüsünü engellemeden çalıştırın​
  • Oyuncu girişini simüle edebilme​
Bunları yerine getirmek için önce iskelet prefabrikini TestSuite sınıfına eklememiz gerekiyor:

C#:
public class TestSuite
{
    GameObject playerPrefab = Resources.Load<GameObject>("Player");
    GameObject skeletonPrefab = Resources.Load<GameObject>("ArmedSkeleton");

    ...
}

İkincisi ve girdiyi simüle edeceğimiz için testin oyun döngüsünü engellemesine izin veremeyiz. Bunun nedeni, testin oyunun 1 karesinden fazlasını kapsaması gerekecek.
Bunu başarmak için, eşyordamları kullanmamıza izin veren UnityTest özniteliğine sahip yeni bir test ekleyeceğiz:

C#:
[UnityTest]
public IEnumerator TestSlashDamagesSkeleton()
{
}

Şimdi bir oyuncu ve bir iskeleti somutlaştıralım:

C#:
[UnityTest]
public IEnumerator TestSlashDamagesSkeleton()
{
    Vector3 playerPos = new Vector3(2f, 1f, -1f);
    Quaternion playerDir = Quaternion.identity;
    Vector3 skeletonPos = new Vector3(2f, 0f, 1f);
    Quaternion skeletonDir = Quaternion.LookRotation(new Vector3(0f, 0f, -1f), Vector3.up);

    GameObject player = GameObject.Instantiate(playerPrefab, playerPos, playerDir);
    GameObject skeleton = GameObject.Instantiate(skeletonPrefab, skeletonPos, skeletonDir);

    yield return null;
}

UnityTest bir numaralandırıcı gerektirdiğinden bir değer vermenin gerekli olduğunu unutmayın. Ve henüz herhangi bir bekleme kullanmadığımız için boş bir değer elde ederiz.

Ek olarak, iskelet bir oyuncu nesnesine bağlıdır, bu yüzden ona bir tane veriyoruz:

C#:
skeleton.GetComponent<Skeleton>().player = player.GetComponent<Player>();

Testimizin girdileri kullanmasına ve simüle etmesine izin vermek için InputTestFixture sınıfından miras almamız gerekir:

C#:
...
using UnityEngine.InputSystem;

namespace Tests
{
    public class TestSuite: InputTestFixture
    {
          ...
    }
}

Ancak bu sınıf varsayılan olarak mevcut değildir. Bu yüzden ilgili referansları test derlememize eklememiz gerekiyor.

Testler klasörünüze gidin ve Testler montaj tanımını seçin.
Montaj Tanımı Referansları altında Unity.InputSystem ve Unity.InputSystem.TestFramework ekleyin. Değişiklikleri uygulayın:

2021-03-04_15-09-md.png

Ama bu yeterli olmayacak. bize söylediği gibi, paketi proje bildiriminin test edilebilirlerine eklememiz gerekiyor.

Packages/manifest.json'u açın ve bağımlılıkların altına bir test edilebilir bölüm ekleyin:

Kod:
{
  "dependencies": {
      ...
  },
  "testables": ["com.unity.inputsystem"]
}

Bundan sonra, InputTestFixture'a yapılan referanslar derleme hatalarına neden olmamalıdır. Ancak girdiyi simüle etmek için daha fazla değişikliğe ihtiyacımız var. InputSystem bir fare ve bir klavye cihazı eklemeliyiz. Bunu, sınıfımızın Setup yöntemini geçersiz kılarak yaparız:

C#:
public class TestSuite: InputTestFixture
{
    GameObject playerPrefab = Resources.Load<GameObject>("Player");
    GameObject skeletonPrefab = Resources.Load<GameObject>("ArmedSkeleton");
    Mouse mouse;
    Keyboard keyboard;

    public override void Setup()
    {
        base.Setup();
        mouse = InputSystem.AddDevice<Mouse>();
        keyboard = InputSystem.AddDevice<Keyboard>();
    }

    ...
}

Şimdi testin önemli kısmını yazabiliriz! İlk iskeletin HP'sini kontrol edeceğiz, bir kılıç darbesi tetikleyeceğiz ve HP'nin değişip değişmediğini kontrol edeceğiz. Tüm test daha sonra şöyle görünür:

C#:
[UnityTest]
public IEnumerator TestSlashDamagesSkeleton()
{
    Vector3 playerPos = new Vector3(2f, 1f, -1f);
    Quaternion playerDir = Quaternion.identity;
    Vector3 skeletonPos = new Vector3(2f, 0f, 1f);
    Quaternion skeletonDir = Quaternion.LookRotation(new Vector3(0f, 0f, -1f), Vector3.up);

    GameObject player = GameObject.Instantiate(playerPrefab, playerPos, playerDir);
    GameObject skeleton = GameObject.Instantiate(skeletonPrefab, skeletonPos, skeletonDir);
    skeleton.GetComponent<Skeleton>().player = player.GetComponent<Player>();

    Assert.That(skeleton.GetComponent<Skeleton>().health, Is.EqualTo(100f));

    Press(mouse.leftButton);
    yield return new WaitForSeconds(0.1f);
    Release(mouse.leftButton);
    yield return new WaitForSeconds(3f);

    Assert.That(skeleton.GetComponent<Skeleton>().health, Is.EqualTo(80f));
}

Yaptık! Giriş öykünmesi ile bir test yazmayı başardık. Bu tür testler faydalıdır çünkü sizi oyunun önemli kısımları hakkında bilgilendirirler. Herhangi bir nedenle kılıç iskeletlere zarar vermeyi durdurursa, test onu yakalayacaktır.



Fikstür olarak sahneler

Oyuncu bir kamera görevi gördüğü için hem oyuncunun hem de iskeletin serbest düşüşte olduğunu fark etmiyoruz. Varsayılan test sahnesinde taban olmadığı için bu durum testin yanmasına neden olabilir.

Bunu geliştirmek için, varsayılan bir ortam sağlayan bir test sahnesi kullanacağız. Bu sahne projede Scenes/Sandbox.unity olarak zaten mevcut, sadece Kurulum yöntemimize yüklememiz gerekiyor:

C#:
...
using UnityEngine.SceneManagement;

namespace Tests
{
    public class TestSuite: InputTestFixture
    {
        ...
       
        public override void Setup()
        {
            base.Setup();
            SceneManager.LoadScene("Scenes/Sandbox");

            ...
        }
    }
}

Sahnenin yapı ayarlarında mevcut olması gerektiğini unutmayın. Yoksa aşağıdaki hatayı görürsünüz:

Kod:
Sahne 'Scenes/Sandbox', yapı ayarlarına eklenmediğinden veya AssetBundle yüklenmediğinden yüklenemedi.
Yapı ayarlarına bir sahne eklemek için Dosya->Yapı Ayarları... menüsünü kullanın.

Nesnelerinizin davranışını test etmek için önceden benzer sahneler oluşturabilir ve ardından bunları testlerden yükleyebilirsiniz.

İsteğe bağlı olarak ve işleri biraz daha iyileştirmek için oyuncunun kamerası yerine sahnenin kamerasını kullanacağız. Bu, neler olduğunu görmeyi kolaylaştırır. Bunu yapmak için, Setup yönteminde Player prefabrike kamerasını kullanmayacağımızı söyleriz:

C#:
playerPrefab.GetComponent<Player>().activeCam = false;

Davranışını değil, yalnızca hasarı test ettiğimiz için, test yönteminde iskeleti de devre dışı bırakacağız:

C#:
skeleton.GetComponent<Skeleton>().enabled = false;

Son olarak, TestSuite.cs dosyasının tamamı burada:

C#:
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;

namespace Tests
{
    public class TestSuite: InputTestFixture
    {
        GameObject playerPrefab   = Resources.Load<GameObject>("Player");
        GameObject skeletonPrefab = Resources.Load<GameObject>("ArmedSkeleton");
        Mouse mouse;
        Keyboard keyboard;

        public override void Setup()
        {
            base.Setup();
            SceneManager.LoadScene("Scenes/Sandbox");
            playerPrefab.GetComponent<Player>().activeCam = false;

            mouse = InputSystem.AddDevice<Mouse>();
            keyboard = InputSystem.AddDevice<Keyboard>();
        }

        [Test]
        public void TestPlayerDamage()
        {
            Vector3 playerPos = Vector3.zero;
            Quaternion playerDir = Quaternion.identity; // the default direction the player is facing is enough
            GameObject player = GameObject.Instantiate(playerPrefab, playerPos, playerDir);

            Assert.That(player.GetComponent<Player>().health, Is.EqualTo(100f));

            player.GetComponent<Player>().applyDamage(20f);

            Assert.That(player.GetComponent<Player>().health, Is.EqualTo(80f));
        }

        [UnityTest]
        public IEnumerator TestSlashDamagesSkeleton()
        {
            Vector3 playerPos = new Vector3(2f, 1f, -1f);
            Quaternion playerDir = Quaternion.identity;
            Vector3 skeletonPos = new Vector3(2f, 0f, 1f);
            Quaternion skeletonDir = Quaternion.LookRotation(new Vector3(0f, 0f, -1f), Vector3.up);

            GameObject player = GameObject.Instantiate(playerPrefab, playerPos, playerDir);
            GameObject skeleton = GameObject.Instantiate(skeletonPrefab, skeletonPos, skeletonDir);
            skeleton.GetComponent<Skeleton>().player = player.GetComponent<Player>();
            skeleton.GetComponent<Skeleton>().enabled = false;

            Assert.That(skeleton.GetComponent<Skeleton>().health, Is.EqualTo(100f));

            Press(mouse.leftButton);
            yield return new WaitForSeconds(0.1f);
            Release(mouse.leftButton);
            yield return new WaitForSeconds(3f);

            Assert.That(skeleton.GetComponent<Skeleton>().health, Is.EqualTo(80f));
        }
    }
}




Sonuç

Unity Test Framework'ü kullanmaya başlamak basit bir iş değildir. Ancak umarım bu öğretici ile ilk anlamlı testlerinizi nasıl yazacağınızı öğrenmişsinizdir.

Bu testleri editörden çalıştırmak şimdilik idare edilebilir olabilir, ancak zamanla tüm testlerinizi bir bina hattının parçası olarak çalıştırmanız gerekeceği bir noktaya ulaşacaksınız. Durum bu olduğunda, bir sonraki adım, testinizi büyütmek için Game Conductor'ı kullanmaktır!

Dış bağlantılar:


 
Son düzenleme:
Paylaşım için teşekkürler.
 
Paylaşım için teşekkürler :)
 

Şu an konuyu görüntüleyenler (Toplam : 1, Üye: 0, Misafir: 1)

Geri
Üst