Search Unity

Question Recommended way for playmode tests that load game levels

Discussion in 'Testing & Automation' started by liortal, Jul 8, 2021.

  1. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    I'd like to create play mode tests that exercise the real game scenes (e.g: scenes that are included in the game build, not "test" scenes).

    I tried to create a base class for "scene based" tests, that will load and unload a scene in its [Setup] / [Teardown] methods, it doesn't seem to work perfectly. Here's roughly what my base class looks like:
    Code (CSharp):
    1. [TestFixture]
    2. public abstract class LevelTestsBase
    3. {
    4.     private readonly string sceneName;
    5.    
    6.     /// <summary>
    7.     /// Initializes a new instance of the LevelTestsBase class.
    8.     /// </summary>
    9.     /// <param name="sceneName"></param>
    10.     public LevelTestsBase(string sceneName)
    11.     {
    12.         this.sceneName = sceneName;
    13.     }
    14.  
    15.     [SetUp]
    16.     public void SetupTest()
    17.     {
    18.         SceneManager.LoadScene(sceneName);
    19.     }
    20.  
    21.     [TearDown]
    22.     public void TeardownTest()
    23.     {
    24.         SceneManager.UnloadSceneAsync(sceneName);
    25.     }
    26. }
    1. Should i load the scene as additive or single? single means that the play mode runner instance is lost, right ?
    2. Scenes are not immediately loaded, i think that when a test is executed, the scene did not finish loading yet, as it's done after a delay of 1 frame.. how to address this?
    3. Generally - what are the best approaches for running such a scenario ? Any tips to get started?
     
  2. Warnecke

    Warnecke

    Unity Technologies

    Joined:
    Nov 28, 2017
    Posts:
    92
    Hey. For general scene validation, I would recommend to use EditMode tests, as it is faster. It is also not scene based, so you can just load the scene directly without worrying about what is already loaded.

    An example:

    Code (CSharp):
    1. using NUnit.Framework;
    2. using UnityEditor.SceneManagement;
    3. using UnityEngine;
    4. namespace Tests
    5. {
    6.     [TestFixture(@"Assets/Scenes/Scene 0.unity")]
    7.     [TestFixture(@"Assets/Scenes/Scene 1.unity")]
    8.     [TestFixture(@"Assets/Scenes/Scene 2.unity")]
    9.     [TestFixture(@"Assets/Scenes/Scene 3.unity")]
    10.     public class ValidateScene
    11.     {
    12.         private string sceneName;
    13.         public ValidateScene(string sceneName)
    14.         {
    15.             this.sceneName = sceneName;
    16.         }
    17.         [OneTimeSetUp]
    18.         public void LoadScene()
    19.         {
    20.             EditorSceneManager.OpenScene(sceneName);
    21.         }
    22.         [Test]
    23.         public void HasLighting()
    24.         {
    25.             Assert.That(Object.FindObjectOfType<Light>(), Is.Not.Null);
    26.         }
    27.         [Test]
    28.         public void HasCamera()
    29.         {
    30.             Assert.That(Object.FindObjectOfType<Camera>(), Is.Not.Null);
    31.         }
    32.         [Test]
    33.         [TestCase("Main Camera")]
    34.         [TestCase("Directional Light")]
    35.         [TestCase("Cube")]
    36.         public void HasObjectWithName(string objName)
    37.         {
    38.             Assert.That(GameObject.Find(objName), Is.Not.Null);
    39.         }
    40.     }
    41. }
    This code is set up to have parameters for each class. This allows for running multiple tests on each scene while it is loaded. Note that it does not handle cleanup and would leave the test runner with the latest scene after these tests are done.