Jump to content
Unity Insider Forum

Unit Testing von Monobehaivor Klassen


Bradley

Recommended Posts

Ich will meinen Code etwas solider gestalten und versuche mich gerade in die Unittests mit Monobehaivour heran zu tasten.

Im Moment scheitere ich aber schon daran überhaupt mein Script aufgerufen zu bekommen:

        public void CheckTextInTooltip()
        {
            bool result = false;
            ToolTipText toolTip = gameObject.AddComponent(typeof(ToolTipText)) as ToolTipText;


            result = toolTip.ToolTipTextInputCheck("");
            Assert.IsFalse(result);
        }

 

Der Editor verkündet immer ein NullReference Error.

Dass ich solche Klassen nicht einfach mit New Instanziieren kann ist mir mittlerweile klar.

 

Eine weitere Frage:

Kann ich diese Unittests auch automatisiert in Azure DevOps testen lassen?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Unity hat ein eigenes Test-Framework, das teilweise auf NUnit basiert. Schau dir dazu einfach mal die verfügbaren Tutorials an.

Warum da jetzt eine NullReferenceException kommt, ist schwer zu sagen. AddComponent sieht richtig aus (auch wenn die generische Version etwas schlanker ist). Fliegt die Exception denn in der "result = "-Zeile? Ansonsten könnte höchstens noch, je nach dem wie hier der Kontext ist, gameObject null sein.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Tatsächlich fliegt der Fehler schon bei:

ToolTipText toolTip = gameObject.AddComponent(typeof(ToolTipText)) as ToolTipText;

Der genau Fehlertext:

Zitat

CheckTextInTooltip (0,001s)
---
System.NullReferenceException :
---
at (wrapper managed-to-native) UnityEngine.Component.get_gameObject(UnityEngine.Component)
  at Tests.ToolTipWindow_Test.CheckTextInTooltip () [0x00003] in C:\Users\xxxxxx\Documents\SpaceOperaUnity\Assets\SpaceOpera\Tests\ToolTipWindow_Test.cs:16 
  at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod,object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00032] in <567df3e0919241ba98db88bec4c6696f>:0

 

 

Ich hänge mal die Entsprechende (noch schlampig aussehende) Klasse an.

 

using UnityEngine;
using UnityEngine.UI;

public class ToolTipText : MonoBehaviour
{
    [Header("Einstellungen")]

    [Tooltip("Zeit in Sekunden bis das Tooltip erscheint")]
    [Range(0.0f, 5.0f)]
    public float targetTime = 1.5f;

    [Tooltip("Gibt an ob das Tooltip per Default Aktiv ist")]
    public bool ToolTipAktiv = true;

    [Tooltip("Gibt an ob das Tooltip aktuell aktiv ist oder nicht")]
    public bool ToolTipVisible = false;


    [Header("Zuweisungen")]
    public Text toolTipText;
    public GameObject toolTipPanel;


    [SerializeField] private float deltaTimer = 0.0f;
    Vector3 MousCordOffset = new Vector3(0, 0, 0);

    private void Start()
    {
            
    }

    public void ToolTip(string Text)
    {
        toolTipText.text = Text;
    }


    public void Update()
    {
        if (ToolTipAktiv)
        {
            ToolTipVisible = ToolTipTextInputCheck(toolTipText.text);
            toolTipPanel.gameObject.transform.position = ShowToolTip(ToolTipVisible);
            Debug.Log(toolTipPanel.gameObject.transform.position);

            //if (!ToolTipVisible)
            //{
            //    deltaTimer -= Time.deltaTime;
            //    if (deltaTimer <= 0.0f)
            //    {
            //        ToolTipVisible = true;
            //    }
            //}
            //else
            //{

            //    MousCordOffset.x = Input.mousePosition.x + 20;
            //    MousCordOffset.y = Input.mousePosition.y + 00;

            //    toolTipPanel.gameObject.transform.position = MousCordOffset; 
            //}
        }
    }

    /// <summary>
    /// In abhängigkeit vom Text wird True oder False zurück gegeben
    /// </summary>
    /// <param name="text">Text kommt vom tooltip.text</param>
    /// <returns>Ist text leer, wird False zurück gegeben. Sonst True</returns>
    public bool ToolTipTextInputCheck(string text)
    {
        if (text.Length == 0 || text == null)
        {
            toolTipPanel.gameObject.transform.position = new Vector3(-500, -500, 0);
            deltaTimer = targetTime;

            return false;
        }
        return true;
    }
    private Vector3 ShowToolTip(bool toolTipVisible)
    {
        if (!toolTipVisible)
        {
            deltaTimer -= Time.deltaTime;
            if (deltaTimer <= 0.0f)
            {
                ToolTipVisible = true;
            }
            return new Vector3(-500, -500, 0);
        }
        else
        {

            MousCordOffset.x = Input.mousePosition.x + 20;
            MousCordOffset.y = Input.mousePosition.y + 00;

            return MousCordOffset;
        }
    }

}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Tatsächlich ist Sie eine.
 

using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;


namespace Tests
{
    
    public class ToolTipWindow_Test : MonoBehaviour
    {
        [Test]
        public void CheckTextInTooltip()
        {
            bool result = false;
            ToolTipText toolTip = gameObject.AddComponent(typeof(ToolTipText)) as ToolTipText;


            result = toolTip.ToolTipTextInputCheck("");
            Assert.IsFalse(result);
        }
    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ah, aber du startest die Methode über das Testframework. Ich weiß nicht genau, was das Ding macht, aber irgendetwas sagt mir, dass deine Komponente sich nicht auf einem GameObject befindet. Tests packst du auch einfach nicht in MonoBehaviours. Nimm also die Superklasse da raus und baue dir für den Test ein GameObject.

private GameObject gameObject;

[SetUp]
public void Setup()
{
    gameObject = new GameObject("Test Object");
}

Denke auch daran, das Ding wieder zu zerstören:

[TearDown]
public void Teardown()
{
    Object.Destroy(gameObject);
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Erstmal danke an dich Sascha.

Ich bin jetzt mal ein Schritt weiter gekommen:

    public class ToolTipWindow_Test : MonoBehaviour
    {
        private GameObject toolTip;
        [SetUp]
        public void Setup()
        {
            toolTip = new GameObject("Panel_ToolTip");
            toolTip.gameObject.AddComponent<ToolTipText>();

            //toolTip.GetComponent<ToolTipText>().Start();
            toolTip.GetComponent<ToolTipText>().toolTipText = gameObject.AddComponent<Text>();
            toolTip.GetComponent<ToolTipText>().toolTipPanel = new GameObject("Panel");
        }


        [Test]
        public void CheckTextInTooltip_False()
        {
            bool result = false;

            result = toolTip.GetComponent<ToolTipText>().ToolTipTextInputCheck("");
            Assert.IsFalse(result);
        }

        [Test]
        public void CheckTextInTooltip_True()
        {
            bool result = false;

            result = toolTip.GetComponent<ToolTipText>().ToolTipTextInputCheck("TEST");
            Assert.IsTrue(result);
        }

        [TearDown]
        public void Teardown()
        {
            Object.DestroyImmediate(toolTip);
        }
    }

 

Einziges Problem, das ich noch habe ist folgender Abschnitt:

toolTip.GetComponent<ToolTipText>().toolTipText = gameObject.AddComponent<Text>();

Lagere ich das ganze in eine Funktion aus welche in der zu testenden Klasse ist, und rufe die Funktion im Setup auf, habe ich kein Problem mehr.
Ich wollte das ganze allerdings auch das ganze in der TestSetup machen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...