views:

192

answers:

5

I'm fond of the idea of unit testing but I'm having trouble applying it to game programming. Games are highly stateful and often the code doesn't break itself into distinct units. In my experience, most functions mutate state rather than returning values.

Consider a simple action like playerJump(height). I'd love to have a test suite that checks a large variety of cases to make sure that jumping always works as expected. However this function will likely return no value and have the side effect of, player.velocity.y = -height and checkCollisions(player). I can't think of a clear unit test to build around this.

Is unit testing just not viable in highly stateful applications like games? Are the advantages of unit testing so great that it would be worth programming games functionally?

+6  A: 

"often the code doesn't break itself into distinct units"

That's just poor design. The code doesn't break itself into anything. You, the designer, have to impose a structure on the code so that you can demonstrate that it actually works.

"However this function will likely return no value"

So?

"and have the side effect of, player.velocity.y = -height and checkCollisions(player)."

Then test for that.

"I can't think of a clear unit test to build around this."

Why not? You just gave an excellent specification for the results of the function.

You might need a few mock objects to replace the full-blown Player with a simplified MockPlayer that's easier to test with.

But your specification of behavior was perfect. Just test for the things you described.

S.Lott
Ah I see. I think I'm interpreting "unit testing" too literally. I'm imagining testing the inputs and outputs of each function. Rather, the test could validate constraints on the entire system after a function is called. Thanks, it's always nice to escape my programming funnel vision :)
Kai
@Kai: Since the system's state change is the *side effect* of the function, you're still doing unit testing because the function is tested in isolation. It's very easy to test with Mock Objects. I'm not sure why you'd claim that unit testing is somehow limited to inputs and outputs of proper functions.
S.Lott
+1  A: 

Unit tests can be useful for a lot of the low level libraries you may use with game code but I seriously doubt it is of much use for the higher level stuff. Games are usually simulations and rely on massive amounts of shared state which can't meaningfully be mocked up and tested in isolation. Often functions in games do not return any sort of value that you can instantly check but instead set a process in motion which should complete at some point in the future. Testing such behaviour is worthwhile but requires a significantly different approach to the unit test idea of testing pieces of code in isolation.

Kylotan
This is a clearer description of the problem I was describing, thanks. It may be worth seeing if the process that was set in motion did indeed end as expected, but it seems more time consuming than testing simple function inputs and outputs.
Kai
A: 

Unit testing just doesn't care at all how "stateful" your unit is. You have a more or less self-contained piece of code, and if its input and output vector are huge then testing is difficult. Whether or not these vectors are laid down as states before and after execution doesn't change a bit about the testing. If you want to tell us however that you can't think of a proper way to define test cases like in most simple-minded unit testing tutorials/papers, i.e. the test subject is something like "f(x) = y" , then yes, I agree, you will have a hard time proving that the few (x[100],y[99]) vectors that a human cane come up with yield sufficient coverage (numerics!). Try to formulate integrative properties and invariants and go for automated testing.

slartibartfast
A: 

Take a look at PEX for automated unit test generation. It will generate unit tests for all possible input variations, which will help you test a lot of possible combinations.

Mel Gerats
Isn't PEX .NET only? This question isn't tagged as a .NET question.
Paddyslacker
+1  A: 

Programming is programming. Unit tests are useful for any kind of application because they help you detect and correct errors immediately and efficiently.

There are of course areas of high level behaviour that are difficult to unit test, but that's not really what unit tests are for - they are primarily for checking that individual methods or small parts of the codebase do what they are supposed to do.

For the higher level behaviours, you need to apply other testing approaches (regression testing, for example: feeding a fixed sequence of inputs into the game and then checking that you get the same results every time, or generating camera views at fixed locations throughout a level and checking that they always generate the same image)

Your example of PlayerJump is one such case. You can unit or regression test this by isolating it with constant inputs (programatically place the player character at a fixed location in a simple test scene and fire the jump event, then check that his collisions or final resting place is consistent. By building up a library of different objects the player can jump "at", you can cover a lot of test cases (e.g. that the jump succeeds over a gap of the prescribed maximum-jump distance)

Beyond that, though, games do require a lot of gameplay testing (where real users simply play it). This will find odd cases that you didn't cover with automated tests, but more importantly it will answer a question that automated testing will never answer: Does it "feel" right? Is it "fun"? THese are tests only a human can conduct.

Jason Williams
+1 Mind you unit testing a renderer is nigh-on impossible. Some people use the pixar method and snapshot the same control scene from the same angle with the same lighting and shaders and do an image compare
zebrabox