Blog

Mastering Unit Testing in Unity 3D | by Kristopher C. Tobiasson | Medium

For a professional Unity developer, unit testing is a crucial skill. We all want to validate the quality and correctness of our code and unit testing allows us to do just that. However, it isn’t always clear how to test in certain situations in Unity. For example, MonoBehaviours are not directly mock-able and this can sometimes cause confusion at first encounter. Well, I’m going to shed some light on issues like that in this article as I’ll explain some ways in which we can test just about anything you can imagine in the Unity editor with some useful tricks.

First of all we need to get setup for unit testing in Unity. So we’ll need the following packages installed: High End Home Furniture

Mastering Unit Testing in Unity 3D | by Kristopher C. Tobiasson | Medium

I use Zenject as a DI framework in this example. Whether you choose to use Zenject, any other DI framework or no DI at all it shouldn’t matter.

Now you want to create an assembly definition and call it anything that makes sense to you. I called it Tests. Set the following settings in the assembly definition:

So now we need a unit to test. I’m going to keep things as short and sweet as possible by just setting up a test for a very simple class, but the principles used here can be expanded upon and used in very complex situations. One thing to keep very clear is that we only care about testing the class in question and we should try to mock everything else as much as possible or we can get into a dependency nightmare where you have to create dependencies of dependencies of depend…. I think you get the idea.

I thought it would be straightforward enough to create a basic cooling system for a computer. This is the class that we are going to test:

As you can see, there are just 3 dependencies (the coolingIndicatorLight Image, and the fan and cpuTempControl injected with the Zenject Inject attribute). We can mock the 2 interfaces with NSubstitute, but we can’t mock the Image since it inherits from MonoBehaviour. No problem, we can use Reflection for dealing with the Image as a dependency and we can also use Reflection for accessing and Invoking the GetIntensityColor method.

Here are the 2 interface dependencies and the IntensityLevel enum just in case it wasn’t already clear how the looked:

We don’t care about the concrete versions of those interface dependencies because they are outside of the scope of the “unit” that we are testing against. So, since we only care about the CoolingSystem class, what are the unit tests that we should perform? Well, starting from the top and working our way down, we have the following unit tests:

Now let’s go through that code:

You might notice that I turn the coolingSystem.gameObject back to active just before the first yield statement in each test and that is because I like to wait for all things to be setup before allowing the component I’m testing against to start running any code other than the Inject method.

I hope this article helps give you an idea of some useful tricks you can use while unit testing in Unity.

One thing that I didn’t cover here is to clean up the test scene between unit tests. It is a good idea to do a proper tear down by using the UnityTearDownAttribute and destroying all of the objects that you created for your unit test (not the ones that Unity uses for the test runner though).

In summary, you can test just about anything you need with the help from NSubstitute and Reflection. Sometimes you need to get a bit creative, but where there is a will, there is a way!!

Now you have no excuse to not keep that test coverage up!!

Mastering Unit Testing in Unity 3D | by Kristopher C. Tobiasson | Medium

Stainless Steel Furniture Professional Freelance Unity 3D / Full Stack NodeJS Web Developer | Founder of Everdevs.com | Diehard Dad