Practice on existing bugs/defects.
This is a really tough situation. I've never gone all the way to TDD from nothing before, but in my experience, getting a team to go from no unit tests to proactively writing them has been a very "one step at a time" approach.
First, get them comfortable writing unit tests and knowing really what they are and their benefits. For my teams, it's been best to write unit tests for existing bugs. Current bugs in systems have two things that you need to teach people to write unit tests well:
- an expected precondition and postcondition
- an outcome that currently is not what is expected and violates that precondition/postcondition
This gives members very concrete practice examples. They can write a test before they fix the bug, so that it fails. Then, they can fix the code so that it passes, and fixes the bug. Once they're comfortable with this, then you can get them the rest of the way so that they can write unit tests with no code up-front and then write new code to get their tests to pass.
I think the trick is to give them something to practice on where there are clear method pre/post-conditions. If requirements for methods are fuzzy, it's hard for even experienced TDD people to know exactly where to start. Take it a step at time and you'll get there. Good luck!
BDD adds a cycle around the TDD cycle.
So you start with a behaviour and let that drive your tests, then let the tests drive the development. Ideally, BDD is driven by some kind of acceptance test, but that's not 100% necessary. As long as you have the expected behaviour defined, you're ok.
So, let's say that you're writing a Login Page.
Start with the happy path:
Given that I am on the login page
When I enter valid details
Then I should be logged into the site
And shown my default page
This Given-And-When-And-Then-And syntax is common in behaviour-driven development. One of the advantages of it is that it can be read (and, with training, written) by non-developers -- that is, your stakeholders can view the list of behaviours you have defined for successful completion of a task and see if it matches their expectations long before you release an incomplete product.
There is a scripting language, known as Gherkin, which looks a lot like the above and allows you to write test code behind the clauses in these behaviours. You should look for a Gherkin-based translator for your usual development framework. That's out of the scope of this answer.
Anyway, back to the behaviour. Your current application doesn't do this yet (if it does then why is someone requesting a change?), so you're failing this test, whether you're using a test runner or simply testing manually.
So now it's time to switch to the TDD cycle to provide that functionality.
Whether you're writing BDD or not, your tests should be named to a common syntax. One of the most common is the "should" syntax you described.
Write a test: ShouldAcceptValidDetails. Go through the Red-Green-Refactor cycle until you're happy with it. Do we now pass the behaviour test? If not, write another test: ShouldRedirectToUserDefaultPage. Red-Green-Refactor til you're happy. Wash, rinse, repeat until you fulfil the criteria set out in the behaviour.
And then we move on to the next behaviour.
Given that I am on the login page
When I enter an incorrect password
Then I should be returned to the login page
And shown the error "Incorrect Password"
Now you shouldn't have preempted this to pass your earlier behaviour. You should fail this test at this point. So drop back down to your TDD cycle.
And so on until you have your page.
Highly recommend The Rspec Book for learning more about BDD and TDD, even if you're not a Ruby developer.
Best Answer
This statement is very concerning. Not because it means you developed without TDD or because you aren't testing everything. This is concerning, because it shows you think TDD will slow you down and make you miss a deadline.
As long as you see it this way you aren't ready for TDD. TDD isn't something you can gradually ease into. You either know how to do it or you don't. If you try doing it halfway you're going to make it and yourself look bad.
TDD is something you should first practice at home. Learn to do it, because it helps you code now. Not because someone told you to do it. Not because it will help when you make changes later. When it becomes something you do because you're in a hurry then you're ready to do it professionally.
TDD is something you can do in any shop. You don't even have to turn in your test code. You can keep it to yourself if the others disdain tests. When you do it right, the tests speed your development even if no one else runs them.
On the other hand if others love and run your tests you should still keep in mind that even in a TDD shop it's not your job to check in tests. It's to create proven working production code. If it happens to be testable, neat.
If you think management has to believe in TDD or that your fellow coders have to support your tests then you're ignoring the best thing TDD does for you. It quickly shows you the difference between what you think your code does and what it actually does.
If you can't see how that, on its own, can help you meet a deadline faster then you're not ready for TDD at work. You need to practice at home.
That said, it's nice when the team can use your tests to help them read your production code and when management will buy spiffy new TDD tools.
Regardless of what the team is doing it's not always a good idea to write all possible test cases. Write the most useful test cases. 100% code coverage comes at a cost. Don't ignore the law of diminishing returns just because making a judgement call is hard.
Save your testing energy for the interesting business logic. The stuff that makes decisions and enforces policy. Test the heck out of that. Boring obvious easy-to-read structural glue code that just wires stuff together doesn't need testing nearly as badly.
No. This is "let's do a complete rewrite" thinking. This destroys hard won knowledge. Do not ask management for time to write tests. Just write tests. Once you know what you’re doing, tests won't slow you down.
I'll answer 2 and 3 the same way. When you change the code, for any reason, it's really nice if you can slip in a test. If the code is legacy it doesn't currently welcome a test. Which means it's hard to test it before changing it. Well, since you're changing it anyway you can change it into something testable and test it.
That's the nuclear option. It's risky. You're making changes without tests. There are some creative tricks to put legacy code under test before you change it. You look for what are called seams that allow you change the behavior of your code without changing the code. You change configuration files, build files, whatever it takes.
Michael Feathers gave us a book about this: Working Effectively with Legacy Code. Give it a read, and you'll see that you don't have to burn down everything old to make something new.