4

This is in summary the TDD method:

  1. Write a test
  2. check if thes test fails
  3. write production code
  4. run test

I think that TDD as presented works only in ideal circumstances. I'll take a simple example:

Specification: Write a program that calculates the square root of a number, the user must enter a number. If the number is negative, the program should display an error, and if the number is positive or zero the program should display the number whose square is the number entered, or for decimal number whose square is closest to the number entered.

Writing test

class SquareRootTest {

   private SquareRoot squareRoot;

   public void testNegativeNumber() {    
      assertException(squareRoot.execute(-5);   
   }

   public void testIntegerSquareRoot() {
      assertEqual(squareRoot.execute(9),3);
   }

   public void testDecimalSquareRoot() {
     assertEqual(squareRoot.execute(3),1.732);
   }
}

run failed test

writing production code:

class SquareRoot {

 public double execute(Number number) {
     if(number < 0) 
         throw exception;
     if(number < 1)
         return squareRootLessThanOne(number);
      else
         return squareRootGreaterThanOne(numner);
   }

//private methods....

}

this is when writing production code, I find that I have to deal with the numbers lower than one differently from those numbers greater than 1. So I need to update my tests to reflect this.

Updating test

class SquareRootTest {

   public void testNegativeNumber() {    
       assertException(squareRoot.execute(-5));   
   }

   public void testIntegerSquareRoot() {
       assertEqual(squareRoot.execute(9),3);
   }

   public void testDecimalSquareRoot() {
      assertEqual(squareRoot.execute(3),1.732);
   }

   public void testNumberLowerThanOne() {
      assertEqual(squareRoot.execute(0.04),0.200);
   }
}

If I had found a single algorithm to calculate the square root, I would not change my tests.

The TDD method focuses solely on tests from specifications, yet there are tests that are derived from the implementation, particularly all conditional instructions and all instructions controlled by loops should normally be tested. These tests case can not be detected at the time of specification.

My question: How does TDD will deal with this situation? or is effectivelly a weakness of the TDD?

10
  • 2
  • 18
    What you have described is for many reasons not TDD. Two most obvious are that rather than writing a test, you have started with three, and that you have missed the "Do the simplest possible thing to make the test pass" step and replaced it with "write production code" which is not at all TDD. You have jumped directly to an implementation. By jumping to an implementation your tests will tend to be more tightly coupled to that implementation.
    – David Hall
    Commented May 7, 2013 at 12:06
  • 4
    @Belin: You are supposed to add ONE test (preferably with at most one assertion), write code to make that ONE test pass, and continue on with the next ONE test.
    – Spoike
    Commented May 7, 2013 at 13:12
  • 1
    @Belin Spoike has said what I would have - you should only be writing one test at a time. These tests can come from various places - the spec, known bugs or limitations in the current code, or known parts of the implementation that need testing (for example if you introduce an if statement, you know you need to test both branches). As you add these new tests you will often break (and then fix) earlier tests - this is part of the methodology. Of course TDD is also a pragmatic methodology, so these rules are often breakable, but when learning the approach it is advised to follow them closely.
    – David Hall
    Commented May 7, 2013 at 13:36
  • 1
    @Belin: requirement analysis is not a TDD activity, it is done separately and before you code (but it is up to you if you try to do all analysis beforehand or only for one requirement at a time). Design is something the TDD evangelists claim the test-first approach contains somehow - but IMHO TDD will primarily improve your program's testability, not less, not more. Most other design aspects are not in the focus of TDD - as a good designer you will (still) have to think about a problem, find a solution, and then start coding (TDD style, if you like).
    – Doc Brown
    Commented May 13, 2013 at 21:11

2 Answers 2

20

The TDD method focuses solely on tests from specifications

No. It doesn't. TDD encourages adding tests based on your implementation. At each stage of your implementation you are looking for a test that will fail. You add that test, and then make it pass.

So in your case, when you found that numbers less than one have to be deal with differently, you'd start by adding a test for those numbers which failed your implementation. Then you'd add the less than one version.

2
  • No, Test Driven Development means start with the test and then add implementation. This is not in keeping with the common frameworks for unit testing however, so people have tended to use the term BDD for the original meaning of TDD. Take a look at Cucumber for the concept. What you describe is writing code, and then writing a test to prove what you've done works. BDD says write the test as a "spec" and then write code that fulfils that specification so you know what you've written does what its supposed to, and works too.
    – gbjbaanb
    Commented May 7, 2013 at 19:10
  • 2
    @gbjbaanb, I'm not saying you shouldn't write the test first. In fact, that's what my second paragraph says to do. But you should expect to come up with more tests that you need while writing your code. Commented May 7, 2013 at 21:15
14

One test at a time. You say it should throw an exception if given a negative argument?

public double execute(Number number) {
    throw exception;
}

Now it passes the first test.

You say it should return 3 if given 9?

public double execute(Number number) {
    if (number.equals(9))
        return 3;
    throw exception;
}

Now it passes both tests.

But you know you're not done. You know you've just been putting in dummy values, dummy logic. You add tests to drive it to a correct solution, and you'll know when it's easier to put in the correct solution than to add yet another dummy branch.

I believe the problem you are having in understanding TDD is the thought that all tests are written up front. They're not. Write one, make it pass. Write the next one, make it pass (without breaking the first one). Refactor when green. That is TDD, not translating a full spec into tests and then making them pass.

10
  • At what point analysis or design are made ​​when using TDD? Using the example I gave. When do you analyze and design the algorithm?
    – Belin
    Commented May 8, 2013 at 6:54
  • The design of the square root algorithm is done before or after writing the test?
    – Belin
    Commented May 8, 2013 at 7:11
  • 2
    The process of design is not a momentary event, nor is it a stage. Design happens throughout the course of development, particularly while you are choosing what test to write next. It also happens while you refactor, safely, with tests to ensure your changes don't break existing behavior. Commented May 8, 2013 at 13:39
  • When designing the algorithm to calculate the square root of a number, we can express this algorithm using a pseudo language to draft or write directly in the programming language. In this case at least a test code skeleton is already written before writing of the test. So TDD is not really respected because in TDD is to write the test before the code!
    – Belin
    Commented May 8, 2013 at 16:18
  • Yes, you can do that for design. If you do that, what you are doing is not TDD. If you do TDD, then the process of design is as I have described above. There are many ways to design code; TDD is only one of them. It's well defined and we run into communication problems when we label something that is not TDD as TDD. Commented May 8, 2013 at 17:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.