Test class design in Test Driven Development - tdd

I am trying to make sense of TDD. Say I am going to write multiple test classes along with tens of methods for a small project. There will be hundreds of combinations of test classes and methods that work.Are there best practices, standards or guidance on what test classes there should be? Similarly, any on methods of each class?
I involves in the full lifecycle of web application development.Any recommendations on books or training? Thank you in advance!

In TDD, you don't "plan" to write hundreds of combinations of test classes. What you do is take one of your requirements (often just a tiny subset of a requirement), and write one test that proves it's been met. Your test will fail, because your code doesn't do that yet. Next, you write a little bit of code, just enough to pass the test. And then you refactor that code you just wrote - the goal of this refactoring is to remove duplication, to follow good OO design principles, and to make your code fit your application's architecture.
What you'll find is that you'll think about coding differently. You stop trying to plan out every class in advance. You don't generate huge UML diagrams. Instead, you grow your product to match more and more of your requirements. When all your requirements are met, the code is done.
Getting to your more specific questions, what we do is to have a one-to-one relationship between test classes and production classes. I'm a fan of naming the test classes by suffixing _Test to the class name: the tests for ShippingClass become ShippingClass_Test. That makes the tests for a class easy to find. Inside ShippingClass_Test, there will be several test methods for each method of ShippingClass. Each test method exercises a different flow through the production method. Let's say there's a CalculateShippingFees() method and this requirement has to deal with taxes, tax exempt, and international shipping. Each part of the requirements will drive a new little bit of logic that will result in another test. I might get as far as writing a CalculateShippingFees_TaxExempt_Test, CalculateShippingFees_Taxable_Test, and a CalculateShippingFees_TaxServiceOffline_Test (always write tests for your error handling paths, too.)
But when I get to CalculateShippingFees_International_Test, as I'm refactoring I realize that there are more destinations than I thought, and the method is growing too big. So maybe I extract the destinations into a new class using the Strategy pattern, and then I start writing tests for each of those. Or maybe I discover that our shipping provider has a fee calculator that I can leverage, so I change the code to use it. Making these changes is quick and easy, because I know that as long as all my tests pass, I can change anything I want!
And that's the point of TDD: you evolve the software to meet your needs as you need them. If I built up a giant mental model that said "I'll need a shipping fee tax class, and an international destination, a domestic destination, a customs fee calculator, blah blah blah", I may spend a lot of time building all those classes only to later discover that the shipping provider has an API that gives me all that stuff for free, and I wasted my time writing it. Or maybe I screwed up the initial design, thinking that customs fees would be a part of shipping instead of a part of international destinations. With TDD, as I add the new methods and classes, I put them where I need them when I need them.
There are several good books on the topic. Like #Franck, I also recommend Mezaros' xUnit Test Patterns. Roy Osherove has a pretty good book The Art of Unit Testing. And Freeman and Pryce have Growing Object Oriented Software Guided By Tests. Kent Beck's book, Test Driven Development by Example was kind of the spark and it's pretty easy to follow, but it's getting old and the practices of TDD have evolved past it.

I guess would be better if you start to write your code and you show us where do you think you will have tons of combinations, the recommended books are really awesome and also you will have to take advantage of what unit testing framework are you using, junit(Java) supports parameters for those combinations and Spock(groovy) uses parameter tables that are really awesome

Related

TDD is a top-bottom or bottom-top design?

In my memory, most people told me I should design from top to bottom. If I want to implement a web page, I should image or draw this page on paper and then divide it into some functionality. For each functionality, I try design the external API, and implement their inside respectively.
But in TDD, they say I should consider a very very small functionality(a method?) first, write its test, fail, implement it and pass test. Composing them is the last step. I can't image how it gets good API.
And most strangely, they say TDD is not only unit tests and also function tests. I think it means top-bottom. If there is a functionality A composed of methods B, C and D. Because of TDD I write the function test for A first. But... B, C, D are all unimplemented. Should I use three stubs? If B depends on other three methods?
I used TDD to write some small programs. But when I striked an application with GUI, I got stuck.
Since TDD starts with what you can see from the outside (of whatever item you are working on at the moment), I'm not sure how it could qualify as bottom-up.
Taking TDD to the extreme (e.g., as in XP, aka extreme programming), you would certainly start from the end-user perspective, and only ever write as much code as you need to pass the tests created so far. If you find yourself starting with the tests for some internal function before reaching the point where the higher-level tests (plus good design for the code you are writing to make those tests pass) require this routine, you are working on some other paradigm, not strict TDD – because there was no test telling you to write that method in the first place. Not that this is necessarily a bad thing, but any problems you have with that is not really one of the TDD methodology.
For GUI programming, of course, you have the standard problem of automating tests, even before you created code. I only know of good tools for web apps for that; if you have good pointers on this topic in the desktop case, I'd sure love to see them.
I've been heavily writing rspec tests for my rails projects keeping a ratio of about 1:1.6 between code/tests. I never really had an issue of what to write first or what it depends on. If the method A that i want to write consists of B and C, then i would first implement B and C, again using the proper testing. To me the sequence is not so important as long as the tests are good and precise.
So, I don't really use stubs the way you describe it, but only if the functionality is already there and i just want to bypass/circumvent it.
BTW, it is considered a top-down approach. This is an excerpt from Rspec Book :
If you ask experienced software
delivery folks why they run a project
like that, front-loading it with all
the planning and analysis, then getting into the detailed design and
programming, and only really integrating and testing it at the end, they
will gaze into the distance, looking
older than their years, and patiently
explain that this is to mitigate
against the exponential cost of
change—the principle that introducing
a change or discovering a defect
becomes exponentially more expensive
the later you discover it. The
top-down approach seems the only
sensible way to hedge against the
possibility of discovering a defect
late in the day.
I would say it's top down. Say I had a single PDF that had 4 distinct documents in it and I was writing software to split them into 4 individual documents instead of a single document, the first test I would probably write is:
// Note: Keeping this very abstract
#Test
public void splitsDocumentsAccordingToDocumentType() {
List docs = new DocumentProcessor().split(new SinglePdfWithFourDocs());
assertEquals(4, docs());
...
}
I would consider the DocumentProcessor.split() method to be similar to "A" in your example. I could now implement the entire algorithm within the single method split and make the tests pass. I don't even need "B" or "C" right? Knowing that you're a good developer and you cringe at the thought of that 1500 line method you would start to look for ways to restructure your code to a more suitable design. Maybe you see that two additional objects (responsibilities) could be split out of this code:
1) Parsing the contents of the file to find the individual documents and
2) Reading and writing of the document from the file system
Let's tackle #1 first. Use a couple of "Extract Method" refactorings to localize code related to the parsing of the contents then an "Extract Class" refactoring, pulling out those methods into a class named, say DocumentParser. This could be analagous to "B" in your example. If you'd like, you could move tests related to document parsing from your DocumentProcessorTest to a new DocumentParserTest and mock or stub the DocumentParser in the DocumentProcessorTest.
For #2 it's pretty much lather, rinse, repeat and you'll end up with something like a DocumentSerializer class, AKA "C". You can mock this as well in your DocumentProcessorTest and you now have no file I/O and have test driven a component that has two additional collaborators without having to design your entire class (with individual methods). Notice that we took an "outside in" approach, which really enables the refactoring.
Thanks

Planning unit tests with TDD

When you approach a class you want to write, how do you plan its unit tests?
Are there formal templates which you follow or do you use pen and paper/notepad?
I am looking for some way to let other programmers/QAs know what tests should be implemented (and if something was overlooked it can be easier to spot it).
With TDD, tests drive the feature you are writing. If you're needing to write formal templates for it, then chances are you're not entering into the spirit of things!
TDD should be used to generate the test cases as you write the code. Simply put, before you write the next line of code, encode in a test what the code should do.
Check out Bob Martin's bowling game example which should give you more of a feel for TDD.
I do not think that having a template goes well with using TDD. I assume that you have read Kent Beck's Book on Test Driven Development by Example. If no please do so.
But the general idea is simple. When we start a class, we will have a general idea on the responsibility of the class. This is the steps that we use:
Have a general idea on class
responsibility and use that
information to name the class.
Create a test case for this class.
If you start with a concrete information on what the units inside the class are, just write those stubs inside the class and write test cases for those stubs. Initially all of it will fail and the signatures for most of those methods will change. That's the whole idea.
In most cases, the developer may not have that degree of information. In that case, it's OK to start writing code in the First Test. Once the test passes, then migrate the logic to the class.
So what I am driving at is, the whole point of TDD is to make the development process more organic. The class grows, with the knowledge on what it should do. Having a formal template, or writing things down, will probably not help.
The only thing I could think that you could do, is to sit with your developers before each iteration and come up with a pretty detailed idea on each of the component classes and its responsibilities (we only use this discussion to finalize public APIs).
If you want to know the quality of test cases written by your developer, then you can conduct an ad hoc code review to see if the classes are correctly broken down to units and all the units are tested.
TDD is not the methodology you are looking for ;-)
way to let other programmers/QAs know what tests should be implemented
This statement implies you are after tests, but TDD itself is driven by requirements and produces features - the fact that it also produces a suite of tests is an incidental (but hugely powerful) appendage which happens to result in a regression suite.
Although TDD harnesses 'tests' to drive development of code, you do not need to specify tests up-front. Even if you did (and sometimes is helpful to 'thinking' to do so) your programmer may not need to write all the tests in order to produce the desired behaviour in the code. Indeed, in TDD, you are encouraged to stop work when all the tests pass - you need not keep on writing tests only to find they already pass; that is something akin to makework.
Also, the other side-effect of TDD is in having (and continuously running) a regression suite. If at a later date a bug is found, it makes it easier, just by having a test suite, to write another test which demonstrates the bug with a failing test. Once the bug is fixed, the test should pass - along with all the other tests in the suite.
You cannot commit to TDD and let others do the unit testing. This requirement of yours strongly suggest that You haven't understood the TDD paradigm.
In my (admittedly fairly new) experience
You write test that, if passed, will confirm your initial understanding of the target funcitonality. Not a single line of production code is written at this point.
You then Implement the production code so the unit tests are passed.
If your understanding evolves, you then change your unit tests or/and add new ones
You then implement the changes in the production code so the tests will pass
By then, it is not forbidden to write additional unit tests, if you discover that parts of your production code are not covered.
Remove tests that no longer make sense.
You arrive at beautiful crisp and clean code :o)
TDD is NOT a QA method; It is a way of DEVELOPING. The whole idea is that the unit test guide the development process. So you really can't let others do the unit tests for you.
I start by designing the class first, usually with a simple UML class diagram. I try not to make the diagram just detailed enough so that I can run tests against it (e.g. params and return types specified for each method, and I know how the method's behavior affects object state).
Then, I write unit tests. Generally when it comes to automated testing you should have 1 test method for every method defined in your class. As far as convention goes, if I have a method in my class called myMethod, then my unit test method will be called testMyMethod.
I write unit tests using what I know about the method's intended behavior, and then write the method and check to make sure that it passes the unit test.

TDD Example for Business Apps

I understand the general idea about unit testing and have used it in scenarios where complex interactions were happening in a system, but I still have a question about all of those principles coming together.
We are cautioned about not testing the framework, or the database. Good UI design does not lend itself to non-human testing. UI interaction in general is excluded in MVC frameworks. In many apps what is left?. 37signals talks about extensive unit testing, but in an app like Basecamp or Backpack, what exactly are the types of things being tested through appropriate unit tests? What would 100% code coverage mean in that scenario?
EDIT: I am not tearing down apps like Backpack - they are awesome, but the work seems to go more into the design and interaction instead of complex logic (in fact, they espouse that very idea). In those areas of that app, where CRUD and the hierarchy of which object is related to which pretty much cover it, is the appropriate amount of unit tests zero? Is the point of tests in that case to be another copy of the validation code (required, regex, etc.)?
TDD for business apps works like this.
Write down a business requirement.
Write down a test for that requirement.
Write code that passes the test.
The trick is that there are many junky non-business requirements that don't need extensive testing.
"saves to a database" isn't a business requirement. It's technical.
"activates a button on the GUI for some situation" isn't a business requirement, it's part of the interface.
"backup" isn't a business requirement; it's security or business continuity or something.
Consider a concrete example.
Requirement -- "You can't borrow books until you've paid your fines."
Tests.
Attempt to borrow book with fine.
Attempt to borrow book with no fine.
Code.
class FinesNotPaid( unittest.TestCase ):
def setUp( self ):
# load some fixtures with users, books and fines outstanding.
def test_should_not_checkout_book( self ):
x = TheCheckoutClass()
x.checkoutBook( someBook )
self.fail( "Should have thrown error" )
class FinesPaid( unittest.TestCase ):
def setUp( self ):
# load some fixtures with users, books and fines paid.
def test_should_not_checkout_book( self ):
x = TheCheckoutClass()
x.checkoutBook( someBook )
self.success( )
class NoFines( unittest.TestCase ):
etc.
These are Business Rules implemented by classes that are separate from your database and your GUI. These are classes in an application domain layer.
Your CRUD rules are business rules. You need to test them. However, you don't need to test every database-related feature. You need a few "can I create and persist an object?" tests. You have to trust that the ORM, the Data Access layer and the Database actually work. You don't write tests to exhaustively test the built-in features of the ORM.
Code coverage (100% or 80% or 10%) is largely meaningless. Is software that has tests with 80% code coverage actually 20% more likely to fail? It doesn't work that way. Testing every line of code doesn't cover every logic path, so stop worrying and start testing.
Test the business use cases. If they pass and there's untested code, then -- perhaps -- you wrote too much code.
You're testing to ensure that the business logic (in many apps this is the "service" or "logic" layer) matches up with your business users' description of how the business really works. You're testing to make sure that, for instance, just because you add 6% sales tax to all purchases from Pennsylvania, you aren't also giving a bonus 6% credit when you give someone a gift card.
There is (or there should be) a whole lot of brain juice in the layers of the application that stand between the UI and the database. That's the stuff to test the heck out of.

TDD ...how?

I'm about to start out my first TDD (test-driven development) program, and I (naturally) have a TDD mental block..so I was wondering if someone could help guide me on where I should start a bit.
I'm creating a function that will read binary data from socket and parses its data into a class object.
As far as I see, there are 3 parts:
1) Logic to parse data
2) socket class
3) class object
What are the steps that I should take so that I could incrementally TDD? I definitely plan to first write the test before even implementing the function.
The issue in TDD is "design for testability"
First, you must have an interface against which to write tests.
To get there, you must have a rough idea of what your testable units are.
Some class, which is built by a function.
Some function, which reads from a socket and emits a class.
Second, given this rough interface, you formalize it into actual non-working class and function definitions.
Third, you start to write your tests -- knowing they'll compile but fail.
Part-way through this, you may start head-scratching about your function. How do you set up a socket for your function? That's a pain in the neck.
However, the interface you roughed out above isn't the law, it's just a good idea. What if your function took an array of bytes and created a class object? This is much, much easier to test.
So, revisit the steps, change the interface, write the non-working class and function, now write the tests.
Now you can fill in the class and the function until all your tests pass.
When you're done with this bit of testing, all you have to do is hook in a real socket. Do you trust the socket libraries? (Hint: you should) Not much to test here. If you don't trust the socket libraries, now you've got to provide a source for the data that you can run in a controlled fashion. That's a large pain.
Your split sounds reasonable. I would consider the two dependencies to be the input and output. Can you make them less dependent on concrete production code? For instance, can you make it read from a general stream of data instead of a socket? That would make it easier to pass in test data.
The creation of the return value could be harder to mock out, and may not be a problem anyway - is the logic used for the actual population of the resulting object reasonably straightforward (after the parsing)? For instance, is it basically just setting trivial properties? If so, I wouldn't bother trying to introduce a factory etc there - just feed in some test data and check the results.
First, start thinking "the testS", plural, rather than "the test", singular. You should expect to write more than one.
Second, if you have mental block, consider starting with a simpler challenge. Lower the difficulty until it's real easy to do, then move on to more substantial work.
For instance, assume you already have a byte array with the binary data, so you don't even need to think about sockets. All you need to write is something that takes in a byte[] and return an instance of your object. Can you write a test for that ?
If you still have mental block, lower it yet another notch. Assume your byte array is only going to contain default values anyway. So you don't even have to worry about the parsing, just about being able to return an instance of your object that has all values set to the defaults. Can you write a test for that ?
I imagine something like:
public void testFooReaderCanParseDefaultFoo() {
FooReader fr = new FooReader();
Foo myFoo = fr.buildFoo();
assertEquals(0, myFoo.bar());
}
That's rock bottom, right ? You're only testing the Foo constructor. But you can then move up to the next level:
public void testFooReaderGivenBytesBuildsFoo() {
FooReader fr = new FooReader();
byte[] fooData = {1};
fr.consumeBytes(fooData);
Foo myFoo = fr.buildFoo();
assertEquals(1, myFoo.bar());
}
And so on...
'The best testing framework is the application itself'
I believe that a common misconception amongst developers is, they mistakenly make a strong association between testing frameworks and TDD principles. I would advise re-reading the official docs on TDD; bearing in mind that, there is no real relationship between testing frameworks and TDD. After all, TDD is a paradigm not a framework.
Upon reading the wiki on TDD (https://en.wikipedia.org/wiki/Test-driven_development), I've come to realise that to an extent things are a little bit open to interpretation.
There are various personal styles of TDD mainly due to the fact that TDD principles are open to interpretation.
I'm not here to say anyone is wrong, but I would like to share my techniques with you and explain how they have served me well. Bear in mind that I have been programming for 36 years; making my programming habits very well evolved.
Code reuse is over rated. Reuse code too much and you'll end up with bad abstraction and it will become very difficult to fix or change something without it affecting something else. The obvious advantage being less code to manage.
Repeating too much code leads to code management problems and oversized code bases. However it does have the advantage of good separation of concerns (the ability to tweak, change and fix things without affecting other parts of the app).
Don't repeat/refactor too much, don't reuse too much. Code needs to be maintainable. It’s important to understand and respect the balance between code reuse and abstraction/separation of concerns.
When deciding whether to reuse code I base the decision on: .... Will the nature of this code change in context throughout the app codebase? If the answer is no, then I reuse it. If the answer is yes or I'm not sure, I repeat/refactor it. I will however revise my codebases from time to time and see if any of my repeated code can be merged without compromising separation of concerns/abstraction.
As far as my basic programming habits are concerned, I like to write the conditions (if then else switch case etc) first; test them, then fill the conditions with the code and test again. Keep in mind there's no rule that you have to do this in a unit test. I refer to this as the low level stuff.
Once my low level stuff is done, I'll either reuse the code or refactor it into another part of the app, but not after testing it very thoroughly. Problem with repeating/refactoring badly tested code is that, if it’s broken, you have to fix it in multiple places.
BDD To me is a natural follow on from TDD. Once my code base is well tested I can easily tweak behaviours by moving entire blocks of code around. Cool thing is about my programming habits is that sometimes I move code around and discover useful behaviours that I didn’t even intend. It can sometimes even be useful for rebranding stuff to seem like a completely different code base.
To this end my code bases tend to start out a bit slow and pick up momentum because as I advance toward the end of development I have more and more code to refactor from or reuse.
The advantages for me in the way that I code is that, I am able to take on very high levels of complexity as this is promoted by good separation of concerns. It’s also awesome for writing highly optimised code. However the well optimised code tends to be a bit bloated, but to my knowledge there is no way to write optimized code without a bit of bloating. If the app doesn't need high processor efficiency, there's nothing stopping me from de-bloating my code. I'm of the opinion that server side code should be optimised and most client side code normally doesn't require it.
Going back to the topic of testing frameworks, I use them to just save a bit of compiler time.
As far as following story boards is concerned, that comes naturally to me without actually considering it. I've noticed most devs develop in the natural order of story boards even when they are not available.
As a general separation of concerns strategy, in most apps I separate concerns based on UI forms. For example I’ll reuse code within a form and repeat/refactor across forms. This is only a generalistic rule. There are times when I have to think outside the box. Sometimes repeating code can serve well for making code processor efficient.
As a little addendum to my TDD habits; I do optimizations and fault tolerance last. I will try to avoid using try catch blocks as much as possible and write my code in such a way as to not need them. For example rather than catch a null, I will check for null, or rather than catch an index out of bounds, I will scrutinise my code so that it never happens. I find that error trapping too early in app development, leads to semantic errors (behavioural errors that don't crash the app). Semantic errors can be very hard to trace or even notice.
Well that’s my 10 cents. Hope it helps.
Test Driven Development ?
So, this means you should start with writing a test first.
Write a test which contains the code like 'how you want to use your class'. This class or method that you are going to test with this test, is not even there yet.
For instance, you could write a test first like this:
[Test]
public void CanReadDataFromSocket()
{
SocketReader r = new SocketReader( ... ); // create a socketreader instance which takes a socket or a mock-socket in its constructor
byte[] data = r.Read();
Assert.IsTrue (data.Length > 0);
}
For instance; I'm just making up an example here.
Next, once you're able to read data from a socket, you can start thinking on how you'll parse it, and write a test in where you use the 'Parser' class which takes the data that you've read, and outputs an instance of your data class.
etc...
Knowing where to start writing tests and when to stop writing tests while using TDD, is a common problem when starting out.
I have found that it can sometimes help to write an integration test first. Doing so will help create some of the common objects you will be using. It will also allow you to focus your thoughts and tests, since you will need to start writing tests to make the integration test pass.
When I was starting with TDD, I read these 3 rules by Uncle Bob that really helped me out:
You are not allowed to write any production code unless it is to
make a failing unit test pass.
You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
In a shorter version it would be:
Write only enough of a unit test to fail.
Write only enough production code to make the failing unit test pass.
as you can see, this is very simple.

How do you do TDD in a non-trivial application? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I've read a number of books and websites on the subject of TDD, and they all make a lot of sense, especially Kent Beck's book. However, when I try to do TDD myself, i find myself staring at the keyboard wondering how to begin. Is there a process you use? What is your thought process? How do you identify your first tests?
The majority of the books on the subject do a great job of describing what TDD is, but not how to practice TDD in real world non-trivial applications. How do you do TDD?
It's easier than you think, actually. You just use TDD on each individual class. Every public method that you have in the class should be tested for all possible outcomes. So the "proof of concept" TDD examples you see can also be used in a relatively large application which has many hundreds of classes.
Another TDD strategy you could use is simulating application test runs themselves, by encapsulating the main app behavior. For example, I have written a framework (in C++, but this should apply to any OO language) which represents an application. There are abstract classes for initialization, the main runloop, and shutting down. So my main() method looks something like this:
int main(int argc, char *argv[]) {
int result = 0;
myApp &mw = getApp(); // Singleton method to return main app instance
if(mw.initialize(argc, argv) == kErrorNone) {
result = mw.run();
}
mw.shutdown();
return(result);
}
The advantage of doing this is twofold. First of all, all of the main application functionality can be compiled into a static library, which is then linked against both the test suite and this main.cpp stub file. Second, it means that I can simulate entire "runs" of the main application by creating arrays for argc & argv[], and then simulating what would happen in main(). We use this process to test lots of real-world functionality to make sure that the application generates exactly what it's supposed to do given a certain real-world corpus of input data and command-line arguments.
Now, you're probably wondering how this would change for an application which has a real GUI, web-based interface, or whatever. To that, I would simply say to use mock-ups to test these aspects of the program.
But in short, my advice boils down to this: break down your test cases to the smallest level, then start looking upwards. Eventually the test suite will throw them all together, and you'll end up with a reasonable level of automated test coverage.
I used to have the same problem. I used to start most development by starting a window-designer to create the UI for the first feature I wanted to implement. As the UI is one of the hardest things to test this way of working doesn't translate very well to TDD.
I found the atomic object papers on Presenter First very helpful. I still start by envisioning user actions that I want to implement (if you've got usecases that's a great way to start) and using a MVP or MVC-ish model I start with writing a test for the presenter of the first screen. By mocking up the view until the presenter works I can get started really fast this way. http://www.atomicobject.com/pages/Presenter+First here's more information on working this way.
If you're starting a project in a language or framework that's unknown to you or has many unknown you can start out doing a spike first. I often write unit tests for my spikes too but only to run the code I'm spiking. Doing the spike can give you some input on how to start your real project. Don't forget to throw away your spike when you start on your real project
I start with thinkig of requirements.
foreach UseCase
analyze UseCase
think of future classes
write down test cases
write tests
testing and implementing classes (sometimes adding new tests if I missed sth at point 4).
That's it. It's pretty simple, but I think it's time consuming. I like it though and I stick to it. :)
If I have more time I try to model some sequential diagrams in Enterprise Architect.
I agree that it is especially hard to bootstrap the process.
I usually try to think of the first set of tests like a movie script, and maybe only the first scene to the movie.
Actor1 tells Actor2 that the world is
in trouble, Actor2 hands back a
package, Actor1 unpacks the package,
etc.
That is obviously a strange example, but I often find visualizing the interactions a nice way to get over that initial hump. There are other analogous techniques (User stories, RRC cards, etc.) that work well for larger groups, but it sounds like you are by yourself and may not need the extra overhead.
Also, I am sure the last thing that you want to do is read another book, but the guys at MockObjects.com have a book in early draft stages, currently titled Growing Object-Oriented Software, Guided by Tests. The chapters that are currently for review may give you some further insight in how to start TDD and continue it throughout.
The problem is that you are looking at your keyboard wondering what tests you need to write.
Instead think of the code that you want to write, then find the first small part of that code, then try and think of the test that would force you to write that small bit of code.
In the beginning it helps to work in very small pieces. Even over the course of a single day you'll be working in larger chunks. But any time you get stuck just think of the smallest piece of code that you want to write next, then write the test for it.
I don't think you should really begin with TDD. Seriously, where are your specs? Have you agreed on a general/rough overall design for your system yet, that may be appropriate for your application? I know TDD and agile discourages Big Design Up-Front, but that doesn't mean that you shouldn't be doing Design Up-Front first before TDDing your way through implementing that design.
Sometimes you don't know how to do TDD because your code isn't "test friendly" (easily testable).
Thanks to some good practices your classes can become easier to test in isolation, to achieve true unit testing.
I recently came across a blog by a Google employee, which describes how you can design your classes and methods so that they are easier to test.
Here is one of his recent talks which I recommand.
He insists on the fact that you have to separate business logic from object creation code (i.e. to avoid mixing logic with 'new' operator), by using the Dependency Injection pattern. He also explains how the Law of Demeter is important to testable code. He's mainly focused on Java code (and Guice) but his principles should apply to any language really.
The easiest is to start with a class that has no dependencies, a class that is used by other classes, but does not use another class. Then you should pick up a test, asking yourself "how would I know if this class (this method) is implemented correctly ?".
Then you could write a first test to interrogate your object when it's not initialized, it could return NULL, or throw an exception. Then you can initialize (perhaps only partially) your object, and test test it returns something valuable. Then you can add a test with another initialization value - should behaves the same way. At that time, I usually test an error condition - such as trying to initialize the object with a invalid value.
When you're done with the method, goes to another method of the same class until you're done with the whole class.
Then you could pick another class - either another independent class, or class that use the first class you've implemented.
If you go with a class that relies on your first class, I think it is acceptable to have your test environment - or your second class - instantiating the first class as it has be fully tested. When one test about the class fails, you should be able to determine in which class the problem lies.
Should you discover a problem in the first class, or ask whether it will behave correctly under some particular conditions, then write a new test.
If climbing up the dependencies you think that the tests you're writing are spanning over to many classes to be qualified as unit-tests, then you can use a mock object to isolate a class from the rest of the system.
If you already have your design - as you indicated in a comment in the answer from Jon LimJap, then you're not doing pure TDD since TDD is about using unit tests to let your design emerge.
That being said, not all shops allow strict TDD, and you have a design at hand, so let's use it and do TDD - albeit it would be better to say Test-First-Programming but that's not the point, as that's also how I started TDD.

Resources