Testing in Unity

I have decided to finally become a good developer and include some automated testing in my Unity projects. I’ve previously built some testing for a website, but unit testing for games is slightly trickier for a couple of reasons. For a start, games at a certain level are typically trying to simulate complex environments, instead of performing linear chains of actions. Also, the games that I like creating make heavy use of emergent behaviour, which is by its very nature difficult to test. If something were predictable enough to test simply, it wouldn’t be much fun to play.

I started my adventure into unit tests working on a system for adventurers navigating their way through a grid-based room, and fighting various monsters that are move towards them. Eventually, this will be used for a game in which you play an evil villain managing a dungeon, in the hopes of attracting and slaying enough adventurers to make payroll. Thus, adventurers are fully autonomous, which makes them perfect for testing. At the moment, there isn’t a whole lot of complexity that needs testing, so the point of this exercise was more to ensure that the process of creating tests was fluid and easy.

After some Unity-specific testing setup, I built some simple cases to make sure everything was registering with the room correctly, that the adventurer was capable of winning combat, and that they were then capable of making it to the exit of the room.

An adventurer (green) making their way through a dungeon room, slaying an evil goblin (red) as they go. The art in this is, in my humble opinion, quite impressive.

An adventurer (green) making their way through a dungeon room, slaying an evil goblin (red) as they go.

The art in this is, in my humble opinion, quite impressive.

These tests can be run at any time automatically and quickly. This will become especially useful as the pathfinding gets more complex. Right now, it just uses a simple A*, but I plan on making it much more sophisticated by adding shifting weights, changing the view of the room for each individual at any particular time. Adventuring parties will try to stick together, favor pathways, and balance risks and rewards based on their motivations and histories with the dungeon. Your monsters might be so terrifying that they turn their foes without shedding blood, or the lack of adequate break room snacks might make them unwilling to put 110% into slaying.

Regardless, there are going to be a lot of numbers and systems interacting in hopefully pleasantly unexpected ways. This opens up the possibility that they may interact in game breaking ways, and as much as I like confused adventurers wandering in circles, it could get boring rather quickly. Automated testing will make it possible to catch those problems intentionally.

Many discussions of code testing talk about the benefits that come with merely writing a functional test, even if it never run. I am already seeing this in at least one place. A common pattern in Unity development is to use a singleton that will automatically instantiate itself into Unity when needed, basically giving static class access but looped into Update() and such. I use this to easily convert screen-space mouse coordinates to grid-space, store grid parameters, etc. There is often some configuration needed (e.g. grid space size), which typically gets exposed to the inspector in order to facilitate easy editing.

But, this means that they must be setup in the inspector, which means they must be created ahead of time for each new scene. This isn’t too bad, I usually just have a prefab with the settings I want, but it’s far from ideal. More immediately, it makes testing impossible, because tests are run starting in a blank scene and having to set up each singleton in code manually would be rather terrible. Thus, I have to put the default values in the actual code, which turns out to be better for the project as a whole.

As the game grows more complex, I’d ultimately like to build a system where it will play itself for a few hours, to allow for a wide range of permutations of possible game state. Throughout, there can be continuous checks that verify and record a wide range of things, from validating that math isn’t broken, to ferreting out potentially un-fun gameplay situations that could need some design love. In order to build that though, the game needs to actually exist, so building more game is the plan moving forward.

Previous
Previous

Pathfinding: Beyond A*

Next
Next

Water 1