Monday, February 11, 2008

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.



TDD
Monday, February 11, 2008 11:17:18 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]  | 
© Copyright 2010, John E. Boal