7

I'm implementing the view transformation part of a graphics pipeline (basically a matrix which translates coordinates from world coordinates to camera coordinates given a camera position and direction).

Other than the simple case where the point has the same coordinates if the camera is at [0, 0, 0] pointing towards [0, 0, 1] I can't seem to come up with any obvious test cases. Essentially it seems like there's no way of describing what should happen other than the implementation itself.

Any ideas?

  • Can't you just take a few sets of world/camera coordinates and verify that your transformation function turns one into the other? – Ixrec Mar 8 '16 at 22:01
  • I can't get world / camera coordinate pairs without the implementation except in the trivial case described above. I guess I could try and get a few by hand, check them very carefully, and save them as golden tests. – JonathanR Mar 8 '16 at 22:01
  • Maybe. Or maybe you just don't unit test these functions, then. Doing so would appear to serve little utility. – Lightness Races in Orbit Mar 8 '16 at 22:07
  • Also keep in mind that one of the purposes of unit tests is to make future changes safe. The solutions below present some good alternatives, but even if there is literally no other alternative but your own implementation, writing the tests using numbers from that implementation is still guarding again future changes subtly breaking the calculation. This is similar to writing unit tests for legacy code, where their primary goal is making sure that existing functionality other systems depend on doesn't change, more than being provably correct. – GrandOpener Oct 10 '18 at 15:32
11

In the past, I have found that using a spreadsheet application such as Excel to generate test data has been very useful for testing mathematical code.

Writing the same mathematical model twice using two different tools (a programming language and a spreadsheet) helps you spot any mistakes, and ensures that the test data you generate is independent from your code.

Better yet - if you can ask somebody else to do this for you, you'll get an extra pair of eyes on the formula in the spreadsheet, and it will make sure your tests are completely independent.

You can also use Excel to make sure that your generated test data is formatted in a way which is really easy to copy+paste into your unit tests.

Also consider invalid inputs, exceptions and error codes. Your unit tests are there to protect your error handling and validation for "impossible" values (including null references etc.) too.

  • 3
    there are probably a few trivial edge cases as well which could be verified mentaly, point is behind camera etc – Ewan Mar 9 '16 at 0:05
  • A problem I've had with this approach in the past is when two different implementations handle floating point operation rounding differently. The calculation results are functionally the same but, because they aren't equal, the tests fail. – MetaFight Mar 9 '16 at 3:32
  • 2
    @MetaFight that applies to any floating point test - don't test for equality – Mark Mar 9 '16 at 10:22
  • @Mark, actually, you're right. Good point. – MetaFight Mar 9 '16 at 13:25
10

There are a couple of things you could try:

  • Try to find some example values that are "obviously correct" (in the sense that any future maintenance programmer can easily see that and why they are correct, and verify their correctness in their heads without using a calculator)
  • Look up the paper your algorithm comes from and see whether they have examples listed there, if yes, convert them into test cases (and put references to the paper in the documentation comment of the test method)
  • Provide "obviously correct" 1:1 translations of the algorithm from the paper in one or more separate very high-level language(s) (Matlab, Mathematica, Idris, Haskell, Julia, Python, …) and write a script generating test cases using those "obviously correct" implementations. The script should be written in such a way that it can be easily verified that the generated test cases are correct.
  • Try to find the simplest, closest, 1:1 translation of the algorithm (or equation) into your test language, and use that to test the actual implementation.

In the latter case, it may very well be that the implementation in the test case and the implementation in the production code end up being identical. However, that should only be a coincidence, not a goal. You should not copy&paste the implementation.

Now, why is such a test case, where the code in the test and the code in the production code are identical, beneficial? Well, quite simply: code changes. Tests usually don't.

If there is one thing that is true about any part of any graphics pipeline, then it is that it is too slow. Now, you're probably thinking: "my code isn't too slow!" And you're probably right. For your use case. For now.

But believe me: sometime, somewhere, someone will have some crazy idea. Maybe they want to use your library for real-time video processing in an eye implant powered by the bio-electric energy of the human eye, and thus with a seriously constrained power budget (and thus a very slow processor). Maybe it's an art project and they want to render real-time video onto the entire Chinese Wall and thus need to be able to render trillions of pixels at 60Hz.

And then you will have to uglify your algorithm. Put in shortcuts. Manually unroll loops. Offload it to the GPU. Rewrite it in assembly. Maybe even implement it in hardware.

However, your unit test will still be the same straightforward, easily reviewable, easily understandable, piece of code, acting as a safety net for all the crazy, ugly things you need to do to your production code, because, well, real-life constraints happen.

8

In cases like these, where the unit test would essentially be duplicating the function, I've often wondered if I should be writing unit tests at all.

What I've come to conclude is that sometimes yes, it is valuable.

In most cases I wouldn't bother with such a test, but for any critical part of a system I would because, although the test itself doesn't seem to offer much utility, it will still alert you when another developer accidentally breaks the function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.