A few questions about unit testing

1.Do you write more or less unit tests in every project whose scale is a bit large?

  1. What do you think about writing unit tests on Unity? Should it definitely be written or is it not a mandatory thing?

  2. What benefit do you see from writing unit tests?

  3. How detailed testing do you do? Do you also test Unity components, image slider rigidbody etc.

  4. Is it mandatory to use the dependency injection framework in a project that will do unit testing frequently or does it make things much easier?

  5. Should it be written as TDD?

I write just enough unit tests or crosschecks to cover what I suspect will be the things I will have issues with going forward.

There is no sense blindly testing all the things. You’ll never get your game done.

If anything is remotely obtuse I either a) unobtusify it, or b) explain what it expects.

Over time you will understand the things that commonly fail and learn how to guard against those failures.

1 Like

While examining TDD, I heard that it actually speeds things up rather than slowing them down in long run.
Reasons for this

  • Since you write the test before writing the code, it becomes clear in your mind what you will do and you don’t write code you don’t need.
    -When you change something in your code, you can see whether it is broken or not, thanks to tests.
    -Forces you to write clean code
    -Serving as documentation

More or less compared to … ?

It’s a yes and no. It depends on what you’re developing.

I find the notion of writing unit tests for a game-specific player controller absurd, unless the controller is either extremely complex or intended to be generic and reusable.

I don’t do gameplay-code testing for the most part, it’s just too damn hard and time consuming with often very little benefit because that code keeps changing due to design requirements and because it’s often okay to have that code heavily dependent (and game-specific) and thus not very testable.

I hardly do tests of MonoBehaviour classes, instead when there’s something that needs testing it’s a regular C# class that a MonoBehaviour instantiates and uses.

If you write your own collection class, like an Inventory or a streaming chunk system or RPG stats and damage calculations, then that ought to be under unit tests. There are design rules that would otherwise be hard to spot, like a fire magic immunity that stops working when you add an ice magic immunity or when combat damage calculations incorrectly factor in armor and thus damage gets increasingly unbalanced the higher the level.

Code automatically becomes less intertwined, more reusable. It’s also allowing you to make large changes with the safety net of confirming that everything still works.

This “ease of mind” is a biggy!

I have never really used DI except for exploring the concept. But the often very awkward, non-relatable API these injection frameworks use makes the whole code so ugly I’d really rather not use them. On top, I have yet to see the benefit. I don’t want references “magically appear” in my code. I want to have that GetComponent etc line in my code. It forces me to think where these references are coming from and whether I really need to have them there or whether there are more efficient ways to structure the prefab/scene.

It’s also super easy to avoid DI by merely having a “reference provider” component on an object.

As for testing I’ve also hadn’t had to test a class that had to rely on injected references. I just never ran into this problem. Perhaps because I find most value in unit testing in the areas where the testable class stands by itself, like a collection.

4 Likes

Many thoughts in my mind have become clear, thank you both for the answers.

You have described the only reasons why testing should be done.
For everything else, the actual game should be the test. It’s the most proper test you’ll ever get to make.

@Dependency_Injection
Basically if you have a feeling that something is so fundamental or so generic that it can be used across systems, test it thoroughly, and yes, this will help you later as well as part of its documentation. When you know multiple things will rely on this for ages, do a proper and independent testing, and you can now move this forward in time, as you’re now free to introduce changes without breaking everything.

If not, keep it simple.

Some more rationale

Let’s say I like to write deeply technical systems for my (potential) games. For example if I make a weirdly complex 3D tiling system that has so many moving parts that, if it was to break in unforeseen ways, it would be easier to abandon the project than to fix any of it. Well I will never use this in my game if I haven’t thoroughly tested it, documented it, and intended it almost as a 3rd party plugin with clear split in responsibilities.

Now my game that lives on top of that has an easier time telling which is which, I can easily delineate between the two projects, I can tell if my high-level logic crosses some boundaries, or if I need more features. And I probably won’t lose enthusiasm if something breaks deep down. The whole point is that I can work on repairs and improvements in the tiling system while making sure that the game which relies on it won’t completely disintegrate.

When it comes to anything in between, like if you have some sort of generic “middleware”, then you’re doing it wrong, in my opinion. This should belong to a game itself, don’t bother with trying to make everything reusable and separate, it doesn’t work like that in the long run, because you will inevitably break some rules, cross some lines, and make a cludge somewhere. You will never be satisfied, so allows yourself to be pragmatic at times. Working against this will kill your enthusiasm by design.

Allow yourself to be able to finish something, even if the architecture wasn’t perfect, in fact especially if the architecture wasn’t perfect. You’ll do better next time. That’s the only strategy that I’ve found to work.

1 Like