Click here to Skip to main content
Click here to Skip to main content

Writing Your First Unit Test

By , 12 Apr 2005
 

Introduction

This is a brief article on getting started with writing unit tests. Rather than getting into coding and the 'how to's, of which there are numerous introductory tutorials, I want to discuss more the zen of unit testing. Hopefully you will find the information here to be of value--specifically, getting the most out of writing unit tests when you haven't ever done it before. I've written a lot of articles on unit testing, but frankly, I don't think they really provide enough guidance for the beginner.

Motivations

The first thing to clearly identify is, why you want to write unit tests. There are a variety of answers.

Good Answers

  • "So my code is tested more rigorously and therefore the product ships with fewer bugs."
  • "So when I make changes to the code, I can have a bunch of automated tests to make sure that I didn't break something somewhere."
  • "It makes my code better if I write the tests first, then write the code to pass the tests."
  • "It makes testing easier. I don't have to run the application over and over simply to get to the point where a block of code is executed."
  • "When something fails, writing a unit test for that failure guarantees that it's fixed for once and for all."

Bad Answers:

  • "Management wants me to start using Extreme Programming."
  • "I dunno. I heard it was something everyone else does."
  • "My code is broke, I'm way over deadline, and we're all desperate."

The good answers are good because they use unit testing to be proactive during the development process and have definite goals. The bad answers are bad because there is no clear motivation or the project is already in crisis mode. In my experience, unit testing will not bail a project out of crisis.

Where Are You In The Project?

This is an important question, because where you are in the project affects the kind of unit tests you might want to first start writing.

  • Not a line of code has been written.
  • We're near the beginning--code has been written, but the architecture is still in flux (heck, even the specifications are still in flux).
  • We're really ramping up now--new programmers coming on board, lots of modules being worked on concurrently, etc.
  • We've got a lot of code written, the architecture is stable, now we're gluing it all together and starting to do stress testing.
  • The application is ready to ship (or is shipping) and we're approaching the maintenance phase and looking at what features we want in version 3001.

If you're a beginner at writing unit tests, target your unit tests to be effective based on where you are in the project:

Not A Line Of Code Has Been Written

If you're here, you should consider the "write the unit test first" approach. I personally find this hard to do, because I think in terms of classes, hierarchies, and object graphs. I don't think in terms of methods much anymore. But I used to. So let's remember how programming was done before objects:

  • We need a function that takes a, b, c as an input and does foo.
  • We need a function that takes x, y, z as an input and returns q.

Pretty much, this is all that modern methods do. They either fall into the category of "actors" that do things on the grand stage of the application, like saving data, firing events etc., or they are "thinkers", like calculating the interest in a loan.

Write A Validation Unit Test

The simplest thing to do, when you are writing the unit test first, is just write a test that validates that if you give good input, you get good output.

Thinkers

It's easiest to do this with "thinker" methods, because they don't do anything but process the input. You don't have to test anything else except the output.

Actors

Actors are harder to work with.

The Talker

Let's say you have a method that is supposed to open a socket, or a database connection. How do you test that? Well, with actors, you have to do something a bit backwards. You instead test to see how the method handles failures. For example, if you give the OpenConnection method good parameters, you really can't test that it succeeded. But if you give it bad parameters, you can test that it fails!

The Doer

We all like the expression "don't talk about it, do it!". Actors that actually do tangible things, like "query this table" or "save this data" or "instantiate this object" are more easily tested because you can almost always verify the results independently. Check that the member property has been initialized. Query the table or registry or XML config file yourself to make sure whether the data has been saved. Verify whether the data that you get back is what your unit test put into the database. Things like that.

Write Bad Input Tests

Garbage in, garbage out, right? Wrong! After you write your unit test that validates good operation, before you write your code, write some unit tests that give the method some bad data. Bad connection strings. Things that result in divide by zero. Strings that are longer than you allocated space for in the database field. Stuff like that. Your method should handle these conditions as gracefully as possible. Throw an exception (that's not very graceful, is it, but it's better than crashing the application). Invoke an error handler. See how unit tests can get you thinking about "what if" scenarios, and how you want to handle them?

We're near the beginning--code has been written, but the architecture is still in flux (heck, even the specifications are still in flux)

If you're here, I would suggest that you primarily focus on validation unit testing (see above), because as the architecture keeps changing, you want to make sure that you don't break existing code when you implement the architectural changes. If you're like me, you might not have been paying much attention to testing bad input parameters. But if your still working with prototype code, today's bad input parameters might be tomorrow's valid inputs, so in my experience, until things have settled down a bit, you really want to focus primarily on validating your core code.

Identify Stable, Core Code

What code is the most stable? The least susceptible to architecture/specification changes? This is your core code, and you can start writing the unit tests I described above. You might also consider:

Code Path Testing

Code path testing is great because you can write tests that verify that all the branches of your method are executed. Even better, you can discover branches that are dead!

Identify Unstable, Higher Level Code

It's usually the higher level methods that are constantly being written and rewritten in your prototype. Unit testing is definitely valuable for prototypes, because marketing folk love to get hold of your prototype and entice the customer with a new gadget. The last thing you want is for the demo to break in front of the customer. Plus, prototype code has a nasty habit of being folded into production code. But because it's in such a state of flux, the most effective unit test is simply one that verifies that the code does what it should do when all the inputs are correct. After all, you should be working in a constrained and well defined environment for now rather than in the wild world.

We're really ramping up now--new programmers coming on board, lots of modules being worked on concurrently etc.

This is probably the most difficult space to be in with regards to unit tests. Everyone is working on their task list and everyone is screwing up the implementation, no matter how well the design was specified (unless you practically pseudo-code the design).

Verify The Design Goals

Your unit tests should verify the design goals. Forget about validation unit tests and error handling unit tests. Forget about code path unit tests. What you want to know is, does the code that Joe wrote do what I told him to do? This isn't method-by-method validation, but rather meta-level validation. You want to create the entire test fixture for a particular scenario, do whatever calls are necessary, and verify that Joe's code does the right stuff. For example, if you have a class that is supposed to generate the SQL dynamically for database transactions, and this code is supposed to be smart, so that it will handle foreign key references, etc., then write some meta-level tests that set up different database schemas and see how Joe's code handles things. Frankly, Joe should be the one writing the lower level validation and input unit tests. You want to make sure that the design goals are being met!

We've got a lot of code written, the architecture is stable, now we're gluing it all together and starting to do stress testing

Unit tests are great for stress testing because you can create stressful situations (hopefully preventing customer-inspired stressful situations). If you're at this phase and are just introducing unit testing, then start with something that speaks to where you are in the project--write unit tests that set up stress testing, monitor memory and resource utilization, and measure performance. But before you do all this, you will need to come up with some sort of a pass/fail criteria. How much memory should the application be using when I calculate pi to the 10,000th decimal place? How slow can I tolerate the database response time if there are a 100 million records to sort? That sort of thing.

The application is ready to ship (or is shipping) and we're approaching the maintenance phase and looking at what features we want in version 3001.

At this point, you should be able to give yourself a breather. Go through all the code, write validation tests, then bad input tests, then code path tests, then stress tests. If you're at this point, it should be pretty obvious whether the application meets the design goals or not, so you can pretty much ignore those tests. Do them when you have spec'd out the features in the next version. Actually, in the version after next, because the next version will be a service pack to fix all the bugs you find when you write all those unit tests!

What Does The Unit Test Require?

Most unit tests require some (or a lot) of setup. Ugh. This is the worst part about unit testing. You'll need repeatable data. You'll need files (or the lack of them) with specific content (or lack thereof). You may need connections to other machines, servers, databases, etc. Unit tests are not easy, mainly because you often end up writing another whole application (or so it seems) simply to do all the setup stuff!

Test The Simple Methods First

Instead of getting involved in complicated unit testing, go slowly. Identify methods for which you can write unit tests that don't require any setup. Then move on to unit tests that require only a little bit of setup. And so forth.

Consider Sequencing Tests

Sometimes it's easier to write a series of unit tests, where the first unit test does some setup for the next unit test, and so on. Sequencing the unit tests significantly reduces the amount of work you need to do for each individual unit test. The first unit test to fail in the sequence stops the entire sequence. Unfortunately, the only test engine that I know that does sequence testing is mine (AUT).

Organize Your Setup Code

Your setup code should be well organized. Don't copy and paste into each unit test--write static methods in a separate assembly so that it's easy for every unit test assembly to access the setup functions. In other words, treat your unit tests with the same respect and diligence as you would your product code.

Writing Your Second Unit Test

Most likely, your first unit test, unless it's really trivial, is going to require calling some other code in the application to do some setup stuff. Have unit tests been written for that code? This is a very easy way of figuring out what to do next.

Best Practices

Here's some things you should get into the habit of doing so that unit tests are cost effective:

  • When a unit test fails, fix the code right away.
  • All unit tests pass but the code crashed: write a unit test that demonstrates the failure.
  • Maintain your unit tests! Keep them up to date with your architecture/specification changes.
  • Write your code so that it's easy to write unit tests.
  • Refactor your code when necessary to make it more unit test friendly. This will almost always lead to better code as well.
  • Do not copy and paste from your application code that is needed to do setup!

Some Tools

There are several unit test tools out there, and several products that, when you build your application, will automatically run your unit tests. While searching for various links, I came across a very comprehensive web page.

Of course, there are two glaring omissions! AUT and MBUnit.

Further Reading

Besides my own articles on Advanced Unit Testing, take a look at a few interesting things I found:

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Marc Clifton

United States United States
Marc is the creator of two open source projets, MyXaml, a declarative (XML) instantiation engine and the Advanced Unit Testing framework, and Interacx, a commercial n-tier RAD application suite.  Visit his website, www.marcclifton.com, where you will find many of his articles and his blog.
 
Marc lives in Philmont, NY.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberErik Rude25-Jun-12 10:53 
Very useful top level information. Thanks
GeneralManual,Automation and QTP Projectsmembermallik3221-Feb-10 0:31 
Hi
Please provide links for sample projects and its implementation in an organization level..
 

Thanks&Regards
Mallikarjun N
mallik.namagiri@gmail.com
GeneralThoughts...memberLeslie Sanford28-Jan-06 11:04 
I've been thinking more and more about testing my code before releasing it here at Code Project. There have been times where I've suffered a certain amount of chagrin when someone points out a bug that could have been caught with a simple test.
 
My current approach is to use design by contract for each method in my classes. I look at this in a way as placing unit tests inside the classes. At the begining of each method, I "Require" that all of the preconditions for the method have been met, things like checking that values are in range, references are not null, etc. Usually, I throw an exception if a precondition has not been met.
 
Next, and this isn't strictly a part of dbc, but I've still found it useful, is a Guard section in which conditions that make the execution of the method unecessary are checked. If a guard is true, the method returns immediately. For example, say I have a method that merges two lists. If one of the lists is empty, merging is uncessary, so the method returns. You can design your algorithms to handle these types of situations, but sometimes a guard can simplify an algorithm quite a bit.
 
Next comes the code that does the actual work. Sometimes a few judicious asserts can help make sure everything is running smoothly.
 
Next, I "Ensure" that the postconditions of the method have been met. This can get a little complicated depending on what work has been done. You can find yourself rewriting the algorithm that did the work in the first place just to check to make sure everything went ok. But many times it's just asserting on a few values. I set up these tests to that they are only executed in debug mode.
 
Finally, is the "Invariant" section. Usually, this is a call to an AssertValid method that checks all of the class's invariants to make sure the class is in a valid state. You can place an [Conditional("DEBUG")] attribute on this method so that it is only compiled in debug mode.
 
Honestly, I don't use all of these sections for every method or for every class. Some classes are so simple that they don't need the Ensure or Invariant sections, but I find the Require section necessary for almost every method. At any rate, after awhile, you get a sense of how far you should go for each method.
 
Having all of this scaffolding in place, I next find it useful to write a driver program. This is a program usually with a nice, but basic GUI that tests all of the functionality of the classes. This is where some unexpected bugs pop up.
 
All of this isn't suppose to replace unit tests, but just add extra robustness so that unit tests are a matter of stress testing the classes and allowing them to let you know when something goes wrong.
 
At any rate, as I look at my latest projects, I can see that I need to practise what I preach. Got me some testing to do...

QuestionManagement wants me to start using Extreme Programming?memberworldspawn3-May-05 16:59 
As if that'd ever happen!
 
[worldspawn]
AnswerRe: Management wants me to start using Extreme Programming?memberChristian Graus3-May-05 17:15 
Are you intending to leave, or to wait until they fire you ?

 
Christian Graus - Microsoft MVP - C++
GeneralRe: Management wants me to start using Extreme Programming?memberworldspawn3-May-05 17:19 
Know I thought I might keep doing things their way till the company folds, then collect my redundancy Poke tongue | ;-P
 
[worldspawn]
GeneralAutomated Unit Test GenerationmemberToby Opferman2-May-05 14:45 
The one thing we want to keep in mind is that Unit Test code for a particular function or group of functions can be actually more involved and produce more code the code you're trying to test! What does this mean? Well, if you have bugs in your code you can easily have bugs in your unit test code! It's hard to trust results if your unit tests themselves are flawed.
 
This leads to two glaring problems.
 
1. Can't write unit test code for your unit test code and so forth.
2. Time consuming, infact more than writing the original code.
 
Now, if you've been doing this for years you eventually would develop somewhat of a frame work to thunk most functions that you encounter (Such as "CreateFile", for example, if you tend to sandbox everything) and you can have "tested" and some what trusting Unit Test Framework. However we still have the fact that you need to recompile and develop code everytime you write a new unit test function. What would be nice is perhaps if some type of pre-processor could go over your code and generate an interface module that describes each functional interface. From this interface, could it not have a database of stored types and type ranges? Could this then not be used to generate automagically a unit test or even run a unit test without compiling anything?
 
So, I would opt not to write your own unit tests but do the later and either get a tested and proven framework or (perferably) get a product which can generate unit tests based on schemas.
 
Some references to other products (I am not endorsing any particular unit test framework or application, I am just saying they are out there. You should do research on your own to determine which package would work best for your situation):
http://www.polyspace.com/[^]
 
http://www.ldra.co.uk/index.asp[^]
 
We also have to remember that while unit tests do test the logic confinded to a single module or function they are not good for testing inter-module dependencies and interactions. They are not replacements for system testing, functional, stress tests, and just plain black box testing are good for this area. (i.e. While they validated that your logic works fine it could be setting the wrong UI component, would not expose race conditions, perhaps a handle leak occurs or memory leak when you interact with all the modules, etc.)
 

GeneralGreat StuffmemberAdnan Siddiqi24-Apr-05 11:38 
Marc ,thanks again for another great article,however it would be nice if you provide example of some application project and then the Testing code written for it
 
IT would help to beginners like me who are not clear how to start things when testing
 
Thanks

 
MyBlogs
http://weblogs.com.pk/kadnan
GeneralRe: Great StuffprotectorMarc Clifton24-Apr-05 16:37 
Adnan Siddiqi wrote:
Marc ,thanks again for another great article,however it would be nice if you provide example of some application project and then the Testing code written for it
 
Well, I specifically wanted avoid any examples that tied in to one of the various unit test engines available. I've written a variety of articles on AUT that you can read here on CP, and there's a great "how to" starter guide on the NUnit site.
 
If you have any questions though, let me know!
 
Marc
 
MyXaml
Advanced Unit Testing
YAPO
 

GeneralWhy unit tests are not writtenmemberRoland Pibinger15-Apr-05 9:34 
Marc Clifton wrote:
Most unit tests require some (or a lot) of setup. Ugh. This is the worst part about unit testing. You'll need repeatable data. You'll need files (or the lack of them) with specific content (or lack thereof). You may need connections to other machines, servers, databases, etc. Unit tests are not easy, mainly because you often end up writing another whole application (or so it seems) simply to do all the setup stuff!
 
This is the main reason why unit tests often are not conducted. If you need a (even moderately) complicated setup the tests are simply not written. Period! You can forget unit tests if you need to set up "connections to other machines, servers, databases" (BTW, this sounds more like integration testing). For the same reason unit tests are almost never written for legacy code. Therefore:
 
Write your code so that it's easy to write unit tests.
 
That's it. Write the code for (unit) testability or the code will not be tested.
 
IMO, you don't need testing tools and frameworks like xUnit. They may even make things more complicated. My C++ unit test "framework" mainly consists of the assert macro.;)
 
Best wishes,
R.P.
GeneralRe: Why unit tests are not writtenmemberKevin McFarlane12-Jun-05 4:51 
Roland Pibinger wrote:
My C++ unit test "framework" mainly consists of the assert macro.
 

I've only really just properly started doing unit testing and I'm find that it's taking me some time to get my head round it. I'm using NUnit at the mo and I have in fact used it before - but this was in the context of maintaining code that had already been written. So i was just updating tests and writing the odd new one. This is the first time I've had to do it for brand new code written by me. The developer, Dave Chaplin, says that unit testing takes some experience before you can use it effectively and I'm beginning to see why.
 
One of the conceptual problems I'm having is separating out unit testing from post-condition checking (asserting that a function has done it's job in a general sense). The latter is general, the former specific.
 
Unit tests should be short and simple but a post-condition might conceivably not be. Or at least that's what I've been finding in my code.
 
Kevin
GeneralRe: Why unit tests are not writtenmemberWillemM27-Jun-05 0:16 
Testing in general is difficult, because you should ask yourself (while still designing the methods and general functionality) how am I going to check if this works? It doesn't really matter if you use unit-testing or hand testing, it all takes a little thinking and you need experience to do it more easily.
 
In my opinion you should do three things to check validity of your code:
 
  • Use pre- and post-conditions (only in debug builds)
  • Use unit-testing
  • Use hand test to check the link between user interface and model parts
 
I am getting used to the extreme programming process and we even do a codereview before submitting the code to a set of tests Smile | :) It saved us a lot of debugging time down the road.
 
WM.

What about weapons of mass-construction?
QuestionWhere do you put Unit Testing Code?memberdaffrey12-Apr-05 18:26 
Hello,
 
I'm new to the practice of unit testing and I am curious as to where the Unit Testing code should be located...
 
Do you put it in a separate project so that you don't bloat your compiled class library dlls or .exe's ?
 
What about if you already have a VS.NET solution with 5+ projects? I'd be interested to hear what experienced Unit testers do.
 
Thanks,
 
Darren
AnswerRe: Where do you put Unit Testing Code?protectorMarc Clifton13-Apr-05 0:48 
daffrey wrote:
Do you put it in a separate project so that you don't bloat your compiled class library dlls or .exe's ?
 
Great question, and I should have mentioned something about that in the article!
 
I prefer to put the unit tests into a seperate assembly, as a class library. As you mentioned, this keeps the unit tests out of the application code.
 
Alternatively, you can use #if DEBUG to wrap your unit tests so that the code only shows up when you build the debug version. The advantage here is that you can, for example, write the unit tests for each class in the same file that defines the class (assuming you usually have a single file per class).
 
daffrey wrote:
What about if you already have a VS.NET solution with 5+ projects?
 
This might be a good reason to have a separate unit test project. It can reference all five other assemblies so that all your unit tests run from one test assembly. This is what I typically do.
 
With NUnit, for example, you can run your unit tests from the command line, so you could have a unit test "batch" also. It also might be more useful to run the unit tests of a particular assembly as the post-build step of that assembly.
 
Hopefully that gives you some ideas as to what might work best for your needs.
 
Marc
 
MyXaml
Advanced Unit Testing
YAPO
 

GeneralRe: Where do you put Unit Testing Code?memberdaffrey13-Apr-05 1:11 
Thanks Marc.
 
It's good to hear I was on the right track before I take the plunge and do some actual Unit testing. I've got 7 projects in the one solution to retro-unit test and I was a little hesitant getting started Smile | :)
 
I kinda love just adding new stuff before existing stuff is fully complete (and then going back and fixing everything up last) so I need to get into the discipline of Unit Testing so things are better first time around and bugs don't fall through the cracks because of forgetfulness.
 
And once I get the hang of NUnit I'll move onto Nant and Cruise Control... so much to learn..so little time...
 
Cheers,
 
Darren
GeneralRe: Where do you put Unit Testing Code?memberNarren28-Apr-05 23:05 
I see the point of having separate assemblies; in fact, it appeals to me so much that it's the approach I've been using so far in my testing. But over time, I've started to think about some other stuff, stuff that I think is too important to ignore.
 
It all has to do with public APIs and the visibility of types. Unit tests in a separate assembly obviously can't access your internal types. Now you can use reflection to get around that, but that's really just making life hard for yourself. The code suddenly becomes much much harder to read, dragging attention away from the job you're trying to do - test your own class, that you as the developer really should have perfect access to. Or you can let your types be public, but then you're starting to change the public interface of your class for no good reason, opening up internals that should be encapsulated in your assembly. Yet those internals should obviously be tested - all your classes should be tested, not just the public ones.
 
Now you can say 'yeah, but you should be able to reach everything you need to test through the public API'. Sure, but there are at least two things that make pure public-API testing inadequate in my opinon. First, you want your unit tests to be as focused and simple to set up as possible. Even though your classes are decoupled and lean, configuring your web of objects to match exactly the state required to test that specific, internal class can be unnecessarily cumbersome, resulting in test code bloat and dragging attention away from the purpose of the test. Second, you may want to use fake or mock objects to represent some resource, say, a database or maybe some external device that's not even available on your regular developer box. From an external assembly you're unable to inject your replacement objects unless you change the public API in some way (typically by defining an interface for the resource(s) you want to imitate and allowing an implementor to be passed to some constructor or factory method). Once again, you're exposing implementation details that really should be internal to your code, even though its in the form of an interface. Why should the user of your code see that interface? It shouldn't be generally possible to replace bits and pieces of your code just because you needed to do unit testing.
 
For me, therefore, the conclusion must be to opt for some sort of internal scheme, at the expense of that clean separation. Using '#if DEBUG' is one scheme, tagging your test fixture classes with the conditional attribute is another. I guess I prefer defining my own switch (e.g. called 'UNITTESTING'), so that I can run my unit tests on release builds as well.
 
Thoughts? Comments? Blatant errors in logic?
GeneralRe: Where do you put Unit Testing Code?memberworldspawn3-May-05 17:09 
I might be crazy but, won't all calls to internal methods be initiated by a call to a public method? Internal methods are usually dependencies for other public paths of execution, is this really a problem? Confused | :confused:
 
[worldspawn]
GeneralRe: Where do you put Unit Testing Code?memberNarren4-May-05 1:14 
In my opinion, the answer to both questions is yes. Yes, all calls to internal methods will be initiated by calls to public methods, or else those methods shouldn't be there. But yes, it can still be a problem, since it might be a lot more complex to test an internal method in the context of the public method(s) that use it, than to test it in isolation. As I see it, being able to test an individual method in isolation, regardless of the access property set on it, makes for tests that are clear, succinct and to the point. Having to test it only through the public API makes for tests that are muddled by the code required to set up the object in the right state for reaching the method you want to test. That code has nothing to do with the behaviour of the method you write the test for, and so I want it eliminated.
 
Feel free to disagree, of course!
GeneralRe: Where do you put Unit Testing Code?memberworldspawn4-May-05 13:30 
Eliminated? Interesting choice of words.
 
Fair enough, using public methods only = increased burden of context.
 
Speaking of the horrid burden of context, has anyone come up with an acceptable practice for unit testing an asp.net application? I've looked at nUnitASp or ASPUnit(forget the name), and it's laughably unhelpful. Only supports a minor subset of the WebControls namespace and really is a wet band-aid of a solution. I was running the application test center the other day, and it occurred to me you could generate a series of requests in vbscript using it (or write them urself if ur not lazy) and then (somehow) use them to trigger ur unit tests. I'm having trouble working out how to glue it all together though. Any ideas?
 
[worldspawn]
GeneralRe: Where do you put Unit Testing Code?memberRick5011-Mar-06 9:01 
We also ran into this issue of testing internal methods.
 
Conditionals work, but may be difficult to enforce and maintain as you scale your project and team. We seperated our Tests into a *.Test namespace, e.g. MyCompany.OrderManagement.Data.Tests. Then we have our build scripts (we use nant), build 2 different assemblies, one including the source code with tests, and one that does not (which is separated by a directory). The assembly that does not is shipped onto the next stage. This alleviates the need for everybody to 'remember' to put the conditional in every test source file.
GeneralRe: Where do you put Unit Testing Code?memberInanc Gumus3-Mar-07 15:47 
Why don't you write an article for the stuff you have built up?
 
your life is nearly what you believe

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130617.1 | Last Updated 12 Apr 2005
Article Copyright 2005 by Marc Clifton
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid