sab39

... indistinguishable from magic
effing the ineffable since 1977
Are you mocking me?

Are you mocking me?

10/24/2005

Before I wrote a line of code for cmeScribble I decided that I'd code it the right way. Retrofitting "right-way-ness" onto an existing project is almost impossible, so I was determined not to miss the chance to build it in from day one.

The particular "right way" I had in mind was using Test-Driven Development, or TDD. For anyone unfamiliar with the TDD methodology, the idea is that before you write any code or fix any bug you first write a test or two to make sure the code works or the bug is fixed. The test should fail when you first run it, because the code doesn't work and the bug hasn't been fixed. Once you've written the test and verified that it fails, then you write the code to make it pass.

The advantages of TDD are well-documented elsewhere, but in a nutshell: writing the test forces you to know in advance exactly what you want the code to do, and also as you develop more and more code you have a library of tests to make sure you don't break anything.

I could easily see how to write tests for self-contained functions, but I couldn't figure out how to write tests for user interfaces or database-backed logic. Since cmeScribble is all about building user interfaces from database data, this posed something of a challenge. Maybe I can get away without testing the UI layer, but I can count features that won't need database data in some way on the fingers of Captain Hook's right hand. Okay, I thought, Google to the rescue... but searching for databases and TDD provided lots of people with similar issues and no straightforward answers.

A common suggestion was to use "mock objects". The idea is that you create a "fake" version of your database layer which returns plausible values without actually needing a database. This solves the problem but the downside is that you have to actually write the mock version of each database table, and since cmScribe has over a hundred tables at last count[1] I didn't relish that thought much either.

Facing a potential deal-breaker for something you don't want to compromise on tends to focus the mind, and eventually I hit on a solution. A full SQL database is hideously complex, but cmeScribble will be doing it's database access through nrdo (I'm biased, but I honestly don't see how people can work any other way...) and for 99% of uses, nrdo provides a fairly simple object model over the top of the database. Simple enough that if you don't care about persistence (which in a test situation is actually a bad thing) or performance, it's possible to implement the vast majority of it very simply in memory, as part of the nrdo runtime library and generated code, backed by simple List<T>s. A couple of days of hacking later and that's exactly what I've now checked into nrdo's CVS: If you use the C# 2.0 template and set the configuration setting "NrdoMock" to "True", all your code will run purely in memory, with a clean "database" for each run.

There are a few things missing - at a wild guess I'd say it covers 60% of what you'd want to do right now, and I should be able to get that up to about 90% without too much trouble by filling in things as I need them (after writing tests!). Most of the rest can't be handled automatically (because they'd require a full SQL engine in the mocking layer) but can be done with a little manual intervention (by the programmer providing a C# equivalent of the SQL clause in question; the SQL clause itself doesn't get tested but all the logic around it does).

The most satisfying part of the whole thing was watching it pass the tests I'd prepared in advance :)

[1] cmeScribble will have a lot less because of the "enterprise" features that aren't being included and also hopefully by unifying lots of things that were separate tables in cmScribe, but still.