TDD: etc
"I'm curious by what metric you consider your code to be "worse" than before TDD," Noel Llopis asks. (Cool new logo, btw!)
I said the quality was worse but that was actually a horrible word-choice. I'll go back and fix that post right now, and nobody will ever know. What I meant was that my architecture, design, and style are worse.
I expose things I wouldn't ordinarily expose so they can be visible to the test suites. This could be seen as a problem with C# - there is no 'friend' function, and it's nontrivial to control access to a unit test suite. On the other hand, with C#, I've been using public a lot more often than I would with C++, because C# supports properties - if I decide that thing I made public shouldn't be exposed, I can turn it into a property that wraps the thing I want to hide.
On the other extreme, TDD is making me wrap and/or abstract things I wouldn't ordinarily wrap and abstract! Noel would say this is a good thing, because now I'm getting away from my blob-style code. But I'm a big 'speculative generality is bad', 'premature abstraction is bad' guy, and putting in these abstractions before I actually need them, in my mind, just adds these annoying levels of indirection to the code.
At some point those wrappers will be useful, when we port to other platforms, but I'd rather wait until I'm actually doing the port, and then refactor.
And I guess this is something Noel and I disagree on. For me, TDD is all about:
- Stopping bugs early when they're cheapest to fix. Code quality, here, for me, means fewer bugs.
- The euphoria that comes from writing code that does exactly what it's supposed to. (Chuck Tolman, at Treyarch, writes code so solid that once he's finished it, he usually doesn't ever have to come back to it again, unless somebody wants a new feature. I called it "Chuckian code". The ability to do this just comes to him naturally. I need the test suite.)
- Putting scaffolds in that run quickly so I can iterate on the function I'm working on rapidly.
- Improved understanding of the code in general.
- Having the courage to make fairly scary changes even when deliverables are due.
Bobo wants to know what XNA stuff we mock or fake:
We have a very light wrapper around some of GraphicsDevice. We wrap SoundDevice. We wrap the controller, and I'd do that even if we weren't using TDD, because the XNAGS controller class doesn't quite behave the way I'd like. We wrap the certification and network library. Most of this is "faking" rather than "mocking", and it's there to prevent the XNAGS stuff from doing, well, any XNAGS stuff in our test suite. We want to test our code, and so we just want XNAGS to not be there at that time.
Arne mentions how problematic it is to get network games under a test suite. I haven't done it either, but I do know a guy who works on an online game, and he's the test engineer for the network code. So he has a master server that runs test scripts on the dev kits to make sure they can host, connect, and play - automated testing, boom.

I'm not sure how your testing, but could you make your unit tests in a partial class (of the class you are testing) so that they are in a separate code file that you can leave out of the final build, but they have full access to all the internals of the class you are testing? (during development)
Posted by:Dan MacDonald | August 31, 2007 at 12:50 AM
You should look into friend assemblies in C#, which allow an assembly to give internal access to another assembly.
Posted by:Andy Larder | August 31, 2007 at 02:35 AM
What you're looking for is the InternalsVisibleTo assembly level attribute. I generally have my assembly and then a seperate test assembly. I give my assembly an internalsvisibleto attribute identifiying my test assembly, this at least gives my test assembly access to internal methods such that you don't have to make things public you wouldn't normally expose...
On the other hand if you wanted to be crafty a bit of reflection would work too, if I recall the test framework in VS Team Suite provides this functionality for you.
Posted by:Bobo | August 31, 2007 at 06:34 AM