| RED. Why does it
have to fail first? |
| |
Can't we just skip this step?
Nope.
We write the test to fail first... because we need to test... the test
itself! How can we depend on a test that isn't ever going to fail?
Test is failing because there's no code yet.
Write just enough code to make the test pass (hard code the result).
Now that the test is passing, we can refactor.
But... I actually like to take this opportunity to write the next test.
New test is failing because the hard-coded value for the first test doesn't
work (by design).
NOW... we can refactor. Adding just enough code to make both tests work. Here
is where we put in the actual work that makes the code function.
Every time we have a new piece of functionality, we write a test.
Our tests will be an "executable" document on how we (programmers) intend the
code to work.
Even if we didn't get the correct logic to satisfy the requirements (which we
found out in our Acceptance testing)... At least we know what we intended our
code to do.
|
GREEN - Test Passes!
Now that the test is passing, you're half
way there. Move on to Refactoring, and keep the test green each time a
refactoring is completed.
BUGS?
Got a bug? Great! You're just
missing a test then...
DON'T JUST FIX IT! That's why bugs come back..
TDD: Find a bug
->Write a test!
The test expects the correct behavior... and fails of course! NOW fix
the bug ... and the test passes.
That bug will NEVER be back again because your test will always ensure that
the code will do the right thing.
This is the safety net that TDD, Continuous Integration, and test
automation give us. We can now refactor mercilessly...
Onward to Refactoring!
| Refactor
|
| |
Use CI tools. Build often.
Change the order of your tests... do they still all run green? Good tests
are made to be independent. They set-up the system, test it, determine success,
and then CLEAN UP. Especially if there is an error, CLEAN UP is essential.
Be a good test citizen. Just like when hiking - pack it in, pack it out -
After the tests run, always make sure leave things as pristine as you found
them.
|
| Write tests as
appropriate |
| |
We need to make sure to have adequate
unit testing. So what does that mean exactly? It depends on the project.
Some projects will require unit testing for every single control flow, and
some will only require cursory tests. It may vary even from class to class.
An example I give is a DTO class (data-transfer object). This class has no
logic in it, and no functionality - only properties. Do we need to test it? I
would estimate in most cases - no. If we have an automated tool that generates
property tests for it, then great, use it. Otherwise I think it's a low test
risk. Not zero risk though.
Remember when you're so gung-ho about testing that you generate all those
unit tests... those tests will have to be maintained along with the mainline
code... Test what makes sense, but don't over-do it. Test maintenance costs time
and money too.
|
| |
Make small incremental changes. Once
the method has its functionality completed and the tests are passing, check it
in! Ideally check-in's to the source repository should occur several times a day
(perhaps as often as every couple of hours). If there is a code review process
(and there should be) it should take a very small amount of time to explain and
review one incremental change. If you're using pair programming (and you should
try it if you can) then your code has already been reviewed (pairing is also
called real-time code review), and it's ready to check in as often as every
half-hour to an hour.
There are lots of times when code gets refactored
from a public method to a private one. Many times there are good reasons to
combine and refine the internal workings of a public method into a private one.
Many developers over the years have insisted they should be writing specific
tests on these private methods.
In the .NET world with C#, we can use the
"internal" keyword rather than private to allow only classes in the assembly to
access the method. We can also use the .NET "InternalsVisibleTo" attribute to
allow the test assembly to access the internal methods so they can be tested,
yet not be accessible publicly.
However... if we are using real TDD -
then the code got written as a result of tests that already exist. So, the
coverage should remain virtually the same without adding a single new test. And
that seems like a good plan to me. Plus the whole testing of private methods
thing is a discussion anyway. |