How To Unit-Test A Tile-Map-Class

Started by
2 comments, last by frob 8 years ago

Hello gamedev.net,

while I set the tag as C++, it is more about a general question and beside this specific example, I would be thankful for any resource or explanation of more complex cases of unit-testing.

Is TDD something that I should focus on when I do unit-testing?

How would I test the unit of a tile-map class? What am I looking for?

I read through quite easy examples, where I check values of variables to contain a certain value related to a bank account example.

On the other hand, there seems to be a lot to test during this class, did I construct it too complex already?

The class itself is like this:

There are not many variables: A vertex-array variable and a variable for the tile-map-file.

1. It has an empty constructor.

2. There is a map-loader function

It receives a const char* which will be used to load the file containing all the needed tile-map-information.

Is this already a moment where I would have to unit-test if the const char is empty?

If that is the case, why is not testing if it is null enough without using the unit-test framework?

The map-loader starts to iterate through that information-file. It will look for an entry of a tile-map-image-path first.

Next would be starting to look at all the tile-coordinates which stand in relation to the tile-map.

Would I have to test whether these are even valid coordinates on the image file (for example not outside of the canvas size).

The rest is defining the quads of the vertex, repeating this until the file reached an end.

3. Draw the tile-map function

All it does is opening up the vertex array and starting to draw the tile-map.

This is all the class does and can do.

Still I'm not really sure what to test exactly.

Moreover, would an integration test be a good thing to be added on here, too?

There are so many ways of testing, it gets really overwhelming at first, so I would be happy if someone could clear things up for me : )

Thanks a lot for taking your time to read this, if something is unclear, I will give my best to explain further details or to simplify explanation.

Advertisement

The idea of Unit Testing is basically to exercise the entirely of the (public, at minimum) interface, and that all input parameters to such respond in the anticipated way -- that might mean, for example, that a default-constructed tilemap object has an empty tiles vector, or that attempting to load a file that you know to be missing responds in a certain way, or that a malformed map file responds in a certain other way. You might also test things such as memory reclamation, the level of exception-safety guarantees provided, performance characteristics of certain operations, or any other behavioral guarantee you make -- all of those things can be considered as a part of the interface. You decide what the interface you are promising your users is, and the unit tests attempt to exercise all common and corner cases to verify that you are upholding that promise. What the tests are, exactly, depends on the promises you are making.

In general I would not recommend that a tile-map should be responsible for drawing itself, and so I would not recommend you find it necessary to test its ability to draw, but only its ability to represent its data-model consistently (that is, the vectors and other variables inside of it). In general a tile-map is correct if its data-model is consistent with what you expect, and whether it draws the same pixels is not really a proper question to ask -- in other words, if one of the tile bitmaps changes, the output may be different independently of whether its correctness changes. However, if you must test such things, you could write a bitmap out and compare it to a known-good bitmap of the same map (or compare hashes thereof) -- as long as the same parameters and tile images go in, they should compare equal. As I said though, a better design to begin with would be one in which a tile-map does not actually draw itself (that is, be directly responsible for causing pixels to be put onscreen) -- an alternative design would allow a "drawer" of some description to query the tile-map for the information it needs to draw it.

Integration testing is basically just unit-testing only its concerned with how independent systems fit and work together. If you used such a design as I describe above, where drawing of pixels is separate of tile-map representation, then this interaction would be a good example of something I'd expect to find in an integration test. The main difference between unit testing and integration testing is that you are looking at compound concerns, and sometimes at state that sort of floats somewhere between the subsystems in the interaction (that is, in the glue that binds them together). If you're going to test, then a commitment to testing at all levels is important, though like all things there are diminishing returns at some point and you have to move on. A good target is to test a representative sample of every good or bad input and corner-case you can think of initially, and to add a test for every bug you fix, so that the bug does not get re-introduced later (this is part of what's called regression testing). That strategy should put you in good shape.

throw table_exception("(? ???)? ? ???");


It receives a const char* which will be used to load the file containing all the needed tile-map-information.
Is this already a moment where I would have to unit-test if the const char is empty?
If that is the case, why is not testing if it is null enough without using the unit-test framework?

Does your class handle a null string?
Does it display an error message or take some other execution path if the string is null?
If this is the case then yes you can test it. If you just want to test to make sure that the string is never null then this isn't really a Unit Test as you are testing data and not your code.


Would I have to test whether these are even valid coordinates on the image file (for example not outside of the canvas size).

No as this is just data validation. If your class can handles coordinates outside the canvas area in an elegant manner (rather than just crashing) then you can test that but, testing if the contents of a file contain the data you expect isn't really what Unit Tests are for.


3. Draw the tile-map function
All it does is opening up the vertex array and starting to draw the tile-map.

Does your Tile Map class actually handle its own drawing? This seems like a strange way of doing things.
I'd expect the TileMap to hand drawing off to some kind of renderer class.

The way I'd expect a suite of Unit Tests to be written on a Tile Map class is to use specific Test Maps and Test that after loading certain tiles at certain coordinates are the tiles you expect. I'd also want to test failure conditions so pass in a couple of files with slightly erroneous data to make sure that your Tile Map class fails gracefully.

Unit tests hit the functionality of the class's single responsibility. Exactly how you do it depends on the nature of the class.

There is an amazing book with much of the content online, xUnit Test Patterns, which I strongly recommend if you are interested in building better automated tests. It covers everything from the ultra-quick unit tests that should be quite fast, to patterns used by integration tests, database tests, and other slow-running acceptance-style tests.

This topic is closed to new replies.

Advertisement