This section will introduce you to the hooks in the test framework for before and after the player build.
Sometimes it’s necessary to change settings or prepare assets before a build for Play Mode tests. Similarly, it might be relevant to clean up things after the build. For this the test framework has two hookup points called PrebuildSetup and PostBuildCleanup.
In the Editor, the PrebuildSetup
is invoked before the build and test run and the PostBuildCleanup
is invoked after the tests are completely done. This happens for both Edit Mode and Play Mode tests. When running Play Mode tests on a device, the Cleanup is already run right after the build is done, as the tests are happening in parallel on the device.
The simplest way of ensuring a test has a PrebuildSetup
and PostBuildCleanup
is by implementing IPrebuildSetup
and IPostBuildCleanup
respectively in your test class.
Often the setup and cleanup will be interacting with code in the UnityEditor
assemblies. These are not available when running on a device, but we want our built-in setup and cleanup code to stay in the test class. For this, it’s recommended to wrap the Editor-related code lines in #if UNITY_EDITOR
defines. For example:
public class MyTestClass : IPrebuildSetup
{
[Test]
public void MyTest()
{
}
public void Setup()
{
#if UNITY_EDITOR
UnityEditor.EditorSettings.serializationMode = SerializationMode.ForceText;
#endif
}
}
Note: If the Editor code is not wrapped, then you won’t see any compilation error when running in the Editor, but you will see the compilation error once you try to run the test in a player.
The sample 12_BuildSetupCleanup
contains a Play Mode test for verifying the content of a sceneA Scene contains the environments and menus of your game. Think of each unique Scene file as a unique level. In each Scene, you place your environments, obstacles, and decorations, essentially designing and building your game in pieces. More info
See in Glossary. It is essentially the Play Mode version of the test from the previous exercise.
The test fails because the scene can’t be found. It could be solved by adding the scene to the build settings, but it’s not good practise to add a test-related scene to the build settings, as it could get included when building for non-testing purposes.
Therefore the task is to create a PrebuildSetup
that adds the scene to EditorBuildSettings
and a PostBuildCleanup
that removes it again.
Test the solution by running the test both in the Editor and in a standalone player. You will need to use #if UNITY_EDITOR
to make the code compile for the player.
IPrebuildSetup
interface requires a Setup
method, so be careful that there are no [SetUp]
methods already called that.A full solution is available in the sample 12_BuildSetupCleanup_Solution
.
The full test solution can be done like this:
using System.Collections;
using System.Linq;
using NUnit.Framework;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.TestTools;
namespace Tests
{
public class SceneTests : IPrebuildSetup, IPostBuildCleanup
{
private string originalScene;
private const string k_SceneName = "Assets/MyGameScene.unity";
public void Setup()
{
#if UNITY_EDITOR
if (EditorBuildSettings.scenes.Any(scene => scene.path == k_SceneName))
{
return;
}
var includedScenes = EditorBuildSettings.scenes.ToList();
includedScenes.Add(new EditorBuildSettingsScene(k_SceneName, true));
EditorBuildSettings.scenes = includedScenes.ToArray();
#endif
}
[UnitySetUp]
public IEnumerator SetupBeforeTest()
{
originalScene = SceneManager.GetActiveScene().path;
SceneManager.LoadScene(k_SceneName);
yield return null; // Skip a frame
}
[Test]
public void VerifyScene()
{
var gameObject = GameObject.Find("GameObjectToTestFor");
Assert.That(gameObject, Is.Not.Null, $"GameObjectToTestFor not found in {SceneManager.GetActiveScene().path}.");
}
[TearDown]
public void TeardownAfterTest()
{
SceneManager.LoadScene(originalScene);
}
public void Cleanup()
{
#if UNITY_EDITOR
EditorBuildSettings.scenes = EditorBuildSettings.scenes.Where(scene => scene.path != k_SceneName).ToArray();
#endif
}
}
}
Note that #if UNITY_EDITOR
is also used among the using statements, to allow for a using reference to UnityEditor
.
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.