Practical PlayMode Testing in Unity3D

Deepak Chirammel
XRPractices
Published in
5 min readJun 21, 2020

Automation Tests are an integral part of the Software Development Life Cycle (SDLC). The Unity Test Framework (UTF) enables Unity Users to test their code in both EditMode and PlayMode. The UTF can be run in different target platforms such as Stand-Alone (i.e., from Unity Editor itself), Android, iOS, etc.

The basic setup of the Unity Test Framework, Mocks, Edit Mode Tests, etc, are covered in the earlier article from Kuldeep Singh

Here we will be covering more on the end-to-end integration side of testing in Unity using PlayMode Tests.

LetsPlay Project Setup

This project is an extension of ShowMeTDD wherein we create a simple application to sum two given numbers and automatically calculate the result.

Refer to the commit hash from the project LetsPlay

On Entering values for A and B, it automatically calculates the Sum.

Any application build in Unity on running will be generating frames in a continuous succession one after the other. This is popularly known as FPS or Frames per second. The FPS for any unity application can be configured by modifying the Application.targetFrameRate property.

Unity provides several in-built functions called Event functions like Start, Update, Destroy, etc. These event functions have specific order/sequence of execution which can be extended and used for achieving certain desired goals.

For our use case, in order to calculate the sum of two numbers (A and B) automatically we will be using the Update event function as shown below:

Update event gets fired on every Frame which in-turn calculates the sum

PS: This Update event function is called on every frame. So it's imperative that it should be used judiciously. No CPU intensive or time-consuming code should be used here as it can drastically affect the FPS and make the application slow/crash on different CPU machines or platforms. As a best practice, it's even better to create a coroutine (which are like separate threads) and delegate the script action to the coroutine, so as to free/leave the Main UI thread alone.

Now back to the project, when we run the LetsPlay scene and on entering the values for A and B, the resultant sum is calculated immediately as shown below:

The resultant sum is calculated instantly

So far we have been doing excellent TDD which covers the individual Unit/Blocks and it covers the tests. Here comes the next challenge:
-> How do you write an end-to-end test for the given scenario?
-> How to test Update event which gets fired only on running?

Play Mode Tests

PlayMode Tests allow you to exercise the actual app/game simulation in real and verify that it runs as desired. Let's create PlayMode tests as shown below:

  1. Select the PlayMode Tab from the Test Runner and create a test assembly folder for the PlayMode Tests.
Creating PlayMode Test Assembly Folder

2. Now create a Test class named “LetsPlayTests” as shown below:

Default Blank PlayMode Test class

PS: For the creation of the end-to-end scenario PlayMode test, we will be using the UnityTest annotation (so that it runs as a coroutine). Before running, we also need to set up and load the actual scene named “LetsPlay”.

3. Let's load the Scene LetsPlay and write a decent end-to-end PlayMode Test

Input values for A and B, Give back the thread control via “yield return null” which calls Update Event

As shown in the above image, we are loading the scene as an OneTimeSetUp. And in the UnityTest, we assign values for the Input Fields A and B, then exits out the current thread via “yield return null”. This in turn will call the Update Event as per the next order/sequence of execution. Thus the sum result calculation step in the Update event gets executed which later is getting asserted/verified in the PlayMode Test.

Note: The complete source code is available in GitHub.

General Tips/Tricks for PlayMode Tests

  1. On running the PlayMode Tests for the very first time, we might face an issue saying “Scene couldn’t be loaded because it has not been added to the build settings or the AssetBundle”.
    To fix it, from the menu, open File->Build Settings, and Add the Open Scene.
  2. Loading the Scene might be time-consuming sometimes(in case of heavy computations/bigger scenes/large number of gameObjects in the scene/platform or CPU limitations etc). So accordingly add a WaitForSeconds before executing your tests, so that it waits to completely load the scene correctly.
  3. There are several functions that can be used inside a coroutine such as WaitForEndOfFrame, WaitUntil, WaitWhile, WaitForFixedUpdate, etc which can easily test Unity Event functions. Most of the time, these automated tests will be running as part of some CI via a command line (i.e., non-graphical way in which the Unity Editor is not opened at all). So in those cases, certain features like WaitForEndOfFrame are not supported (no UI means no frames generated). So it's better to go for decent/safer time delays by using WaitForSeconds for supporting different platforms in the PlayMode Tests.

--

--