Unity: Unit testing
Testing is an integral part of a software development life cycle. It helps to make your code robust and maintainable whilst ensuring that unavoidable refactoring doesn’t break the application. But as a small game studio or a lonely indie dev you might never get much needed time and resources to write a couple of tests. Nevertheless, in the long run testing, be it unit, integration or user-acceptance, will undoubtedly greatly contribute to the project well-being.
I’m using Unity 2021.2.13. This tutorial will re-use the code from my previous one — Unity: Create your own Wordle in under 24 hours. Make sure to check it beforehand.
As always, project sources are available at GitHub, find the link at the end of the page.
There are only 2 parts in this tutorial: Unity setup and Writing tests.
Part 1. Unity setup
First and foremost, we should prepare Unity to work with the tests. I personally found it to be slightly more complicated compared to other testing frameworks.
Make sure that the Unity Test Framework package is installed.
Go to Window → Package Manager and locate Test Framework there:
If it is not there, check out this official Unity guide about Package Manager and packages installation process.
Next, we will open a Test Runner panel.
Go to Window → General → Test Runner.
Create EditMode Test Assembly Folder button.
It will create a new folder
Assets with a file
Tests — that’s an assembly definition file. In layman’s terms that’s the file that tells Unity where the test file dependencies are located. As you probably noticed already, the
Tests folder is not placed next to the production code. You can read more about it here.
Tests assembly definition file selected in the Project panel you can already create a dummy Test script
I will go ahead and create the first test file for the
Unfortunately, this script won’t even compile as it cannot resolve the
In order to make the script visible for test we will need to create another assembly definition file. That one will reference our production code.
Go to the Assets → Scripts folder and create it there.
Now go back to the Tests assembly definition and reference it there:
You might be thinking that the test should work now. What happened instead though, is that other production scripts are no longer compiling! The reason for it is simple — the newly created
Game Assembly Definition is missing a few references —
TextMeshPro compilation issues is rather straightforward — it is already available in Unity, so we should just add it to
Note! Check out this post to learn more about why
TextMeshProneeds an explicit reference
At the time of writing there is no pre-created assembly definition for
DOTween, thus we will create one ourselves.
Go to Assets → Plugins → Demigiant → DOTween and create it there:
Now add it to the Game definition assembly:
And finally the code is now compiling and the test can be run!
It is failing at the moment and that’s something we will be looking next.
Part 2. Writing tests
If we check the LetterControl script we will see that it extends
MonoBehaviour, and all of the instances extending it must be instantiated with
GameObject.AddComponent<T>() instead of the
Let’s apply the change and run the test again:
Now it passes successfully!
Before we jump into writing the test cases let me take a break and say a few words about the tests structure. Similarly to most of the Unit test frameworks out there,
NUnit has its own attributes for:
- Setting up the test —
[SetUp]— that’s the step performed just before each test method is called. Its purpose is to prepare the required data for the tests.
- Running the test —
[Test]— that’s the test itself.
- Running the Unity test —
[UnityTest]— this is the framework extension. This type of unit test allows you to skip a frame from within a test (so background tasks can finish) or give certain commands to the Unity Editor, such as performing a domain reload or entering Play Mode from an Edit Mode test.
- Cleaning up after the test execution —
[TearDown]— that’s the step performed after each test method. It is used to reset the state of objects so that tests are not affecting each other.
In order to create an actual test case you will be using
Assert class. There are numerous methods available there, such as
IsEmpty and many more. The names of those are quite intuitive, so you should be able to find a suitable one.
Looking at the LetterControl script once again we can see that there are 3 public methods to be tested:
ChangeColorControl. We can also see that the script has 3 components attached:
Note! Ideally, internal components should be mocked. Unfortunately, there is no up-to-date mocking framework available for Unity at the moment.
First, let’s set up the required components — we will create a method with
As you can see, it is a rather tedious setup as we have to make sure that all the components are added to the correct places in the hierarchy. It is important not to forget to call
Awake() after the preparation is done as it won’t be called automatically by the test.
Now when setup is done, we can finally create the first real test case:
Run it in Unity to see the green checkmark meaning that the test has passed successfully!
To keep this tutorial short, only one more test will be created — a tricky one, for the
ChangeColorControl method. Looking at the code you can see that the change of a color doesn’t happen immediately but after a delay — that’s needed to have a beautiful transition animation. But how should we test it then? As it was mentioned before the testing framework provides a handy attribute —
[UnityTest] — that can be used to halt a test execution so the background execution finishes.
Since we need to pause the test for a given amount of seconds we must switch the test suite to
PlayMode from the current
EditMode. Select the
Tests assembly definition and tick the current running platform (WedGL in this case).
The test will make use of
WaitForSeconds yield instruction. One important note here — we cannot compare two
Color objects directly using
AreEqual method unfortunately as the
Color class holds its internal values as floats. And as doubles and floats cannot express every numerical value, they are using approximations to represent the value. Thus we should compare each of the
Color fields using
One last run and now we see two checkmarks:
Well done finishing the tutorial! Now you know how to write the tests in Unity. My personal take on the current state of testing is that it is a rather complex process. Compared to other testing frameworks I’ve used (e.g. JUnit, React Testing Library) Unity testing framework is definitely lagging behind in simplicity and ease of running. Nevertheless, it is a powerful tool that shouldn’t be neglected when working on a big project with a distributed team of developers.
Should you have any questions please leave them in the comments section below.
I’ve used the described approach in Categorle, a Wordle variant where you are guessing a word 4–7 letters long in a given category.
For the most comprehensive list of Wordle-like games and resources online be sure to check out this page.
If you like the content you read and want to support the author— thank you very much!
Here is my Ethereum wallet for tips: