Before starting I’d just like to get it out of the way, yes I know there are libraries out there that do just that, heaps and heaps, I’ve used SDL, I’ve used Ogre3D, I’ve checked out UDK and Unity [I’m into game programming if you haven’t noticed] and I know there’s no need to reinvent the wheel. I don’t want wheels, I like walking and I want to write a lightweight rendering suite using OpenGL and built on [at the moment] the WIN32 API; portability is important and will be addressed by minimizing and localizing API dependent calls.
For this lovely suite I’m taking a different approach than what I usually would and am test-driving it. I’ve never really realized how interesting it would be to do so but I don’t want to complain about trying to force OOD into the WIN32 API. I want to talk about the process I’ve been using, namely the TDD approach.
Again, I’d like to stress here that I’m very much a beginner to TDD and the entire Agile methodology, so these concepts obviously do not represent the actual usage of the methodology [unless they really do and can someone please tell me if they do, because I’d love to know].
Ok, back to the window code.
On papar I made a few quick broadstrokes of the things that I wanted to achieve and the items I would need to have in order to achieve them. The list looks something like this;
GOAL: Render one pixel using OpenGL and the WIN32 API
THINGS I NEED:
3. OpenGL Rendering Context.
So far, so good. What’s the first thing I wanted again? ah yes, a Window. A Win32::Window to be more precise [I like namespaces]. Um… Let’s pretend that I have one already, what’s the first thing I’d like to do with it?
Win32::Window window("TestWindow", "TestTitle", Size(640,480), Position(0,0));
We can see where this is going so let’s just jump the gun. Some refactoring later, adding a fixture or two and I’ve had a window class that had some nice attributes; now what? there’s still no actual window on the screen, obviously I need to create it.
Er… two checks in one call, I don’t like it very much and in my code I’ve actually refactored it away; but for the sake of brevity I’ll keep this test. The easy way to solve this is to just change a boolean value on calling both Create() and Destroy(). And I’ve done just that, TDD stating we need to add just enough functionality in order to pass the test. But… But… ARGH, it doesn’t really help me get an actual Window on the screen, does it???
I’ve banged my head on it for a while, I stared at the code for an hour then I started writing some reflective notes and then, then I had a lightbulb go in my head. Testing return values are only part of the tests [and probably not the most important part] that we have in the arsenal. Tests should also test object-object interactions and my object interacts with the WIN32 API.
A quick search through MSDN and I came up with this test;
CHECK( ::GetClassInfoEx(window.hInstance(), window.Name(), &result) );
Run and… Watch it fail miserably. Now I needed to get this test passing, which means actually writing code to talk with the API. And there you have it, this little bit started me on the road to better understand what [I think] TDD is about.
Writing effective tests isn’t easy, doubly so for when they must test interactions. I’ve written before about needing to make assumptions when writing tests and I really thought that I understood that; I was wrong, the fact I nearly gave up here tells me I was still stuck in thinking about tests from a reverse point of view, meaning that code needs to be tested, rather than tests need to be coded. It’s lucky I talk to myself because what brought me to this test was a fairly simple question.
"Ok Amir, now that you've created the window, can you ask the WIN32 API to check whether its there or not?"
Next post would be about the other interesting thing that came up from test-driving the Win32::Window.
The heart of the dragon is screaming awaiting, to write the black last page