Unit Tests Part 2: What to Focus On
This is part 2 in a series on unit testing your game. Part 1 can be found here.
In my earlier post, I described why unit testing is so useful. Today, I want to look at what to unit test.
Important Disclaimer: I’m about to tell you that you don’t need to unit test everything. Not everyone shares that opinion, so I’m sure there will be people who will tell me I’m wrong. That’s fine. In fact, if you feel that strongly about it, please leave a comment and try to convince me.
This is just what I’ve discovered from my own personal experience with unit tests. I’m trying to make a game, not unit tests. Unit tests aren’t deliverables. I’ll use them as a tool, and means to ensuring that I’m making an awesome game, but I’m not going to be religious about writing them. That said, let’s dig in.
The Cost of Unit Tests
In an ideal world, where you have an infinite amount of time to build your code and write all of the unit tests you could possibly ever want, you’d probably unit test pretty much everything. In fact, some people, such as those that adhere to the Test-Driven Development philosophy, feel strongly that this is where you should really be. (In fact, they feel like you should write your unit tests first, then write your code until the unit tests pass.)
But unit tests aren’t free. They take time to write. They take time to run as you make changes to your code. When you refactor your code, your unit tests will probably need to be adjusted. They may have bugs. (Should you write unit tests for your unit tests?) They become pretty complicated if you’re trying to separate individual units, and you need to mock some parts to test other parts. They often dictate a certain design, to allow testing (usually it’s for the better, but not always).
So while there are a ton of benefits, they’re not free. And the more unit tests you have, the higher the cost is. This cost, of course, should be balanced with the benefits that I described in the previous post.
What to Test Most
Since there’s a cost associated with unit tests, my personal opinion is that you need to pick and choose carefully what you write tests for.
There are a few things that if you see in your code, you should immediately write unit tests for:
- Computationally complex methods. If there’s a lot of math involved, or just a lot of algorithmic complexity, you need to make sure that you’ve got tests on this method. These are the kinds of places where mistakes are most often made. Without unit tests, you’ll fail to catch these mistakes.
- Things that are used all over the place. If something is a building block for something else, or especially if it is a building block for lots of things, take the time to make sure you’ve gotten it right.
- Things that you’ve discovered bugs in. While I don’t necessarily recommend testing everything, if you discover bugs in something, you should write unit tests for those pieces. Discovering bugs gives you a hint that it’s not as simple as you had originally supposed, and is worth writing unit tests to account for that. Plus, this will help ensure that as you make changes in the future, these same bugs won’t come back.
- Things that are likely to change. If a method is likely to be re-implemented in a different way, write tests for it. In fact, if you didn’t write unit tests for something initially, but then you need to go back and make changes to it, write unit tests before you make the change. The tests should pass before you make the changes, and should still pass after you make the changes.
On the other hand, there are a few things that you should deprioritize. Obviously, if something shows up on this list, that doesn’t necessarily mean that there’s never a good time to write unit tests for it. Just that these attributes tend to lessen the need for unit tests.
- Anything that is private or protected. If a method is private or protected, most unit testing frameworks don’t usually make it easy to test them. In fact, this is usually by design. You probably should be focused on testing the public (and maybe internal) things that you provide to the outside world.
- Really simple methods. If you’ve got a property that says
public string Name { get; set; }
, you probably shouldn’t test those. You’d, in fact, be testing that the language works according to spec, and those test are already written by someone else. If even your grandma could look at a method and determine that it is right, it probably doesn’t need a unit test. Just reconsider this i you ever rewrite the method to do something more complicated. - Entire systems. Unit tests are designed for units. Not whole systems. You want your unit tests to hit single methods, not run through a complete process.
- GUI interactions. There’s a different category of things called UI Testing, or even Automated UI Testing, that will simulate injecting mouse clicks and keyboard events into your program and check to make sure everything is doing what it’s supposed to. I’m not saying that this isn’t worthwhile, just that your beta testers are pretty likely to pick up on these things, and writing the tests to handle this is usually pretty complicated and changes frequently. In my experience, it’s rarely worth the time.
- Non-critical things that are guaranteed to be changed before the release. There’s no point in spending a bunch of time on writing tests for throwaway code. Just make sure that if you end up not throwing it away, that you eventually write tests for it, if it needs it.
1 Comment
Windwalker
6 March 2013 at 02:11 am
I somehow didn’t buy into unit tests… It feels like indie game development is already consuming, additional load is not very welcome. Unless you have hit the money with your first game and you don’t have to rush for your next game, unit tests feel like a burden. At best, they could be thought of as exercises, or sth. to put into your cv: “I used unit tests in my game. Here:”
Just so you know: these information are extremely valuable to me, and probably everyone who someday wishes to invest their time into game development. I know this is already what you intended, but… How to say it… This place, combined with your wiki, creates a habitat for the mindset required for game development.
Thanks for the sanitarium. Or the zoo. Or the orphanage.