This week's book giveaway is in the OCPJP forum.
We're giving away four copies of OCA/OCP Java SE 7 Programmer I & II Study Guide and have Kathy Sierra & Bert Bates on-line!
See this thread for details.
The moose likes Agile and Other Processes and the fly likes Unit Testing is not LEAN Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of OCA/OCP Java SE 7 Programmer I & II Study Guide this week in the OCPJP forum!
JavaRanch » Java Forums » Engineering » Agile and Other Processes
Bookmark "Unit Testing is not LEAN" Watch "Unit Testing is not LEAN" New topic
Author

Unit Testing is not LEAN

Paul Wallace
Ranch Hand

Joined: Oct 09, 2006
Posts: 40
Ok, the title is quite provocative, but here's my point:

If you follow the Agile practice of Test Driven Development (TDD) rigidly you will write your tests before you write your code.
For the mere mortals, we never get our solution right first time, this inevitably leads to refactoring of your solution. In the TDD approach this will result in you refactoring your tests as well as your application code.
I think this is "unlean". You are spending time refactoring (or disgarding) tests that were never really used. I find it is better to have an iterative approach to TDD:

- write the minimum tests required to allow you to develop your solution
- focus on refactoring your solution to then allow you to write some more tests
- iterate until you have enough test coverage to verify your solution.

Is my approach flawed, or is it LEAN?

Regards

Paul
Marco Ehrentreich
best scout
Bartender

Joined: Mar 07, 2007
Posts: 1282

Hi Paul,

I know what you mean, but I think the experiences you describe depend on how you actually practice TDD. A general principle of TDD is to add only very small features at a time and only if you really find a need for it. This should avoid most of the bigger refactorings and drive the code already very incrementally to a good solution.

If you really have to refactor bigger parts of your code I like to see it as some kind of exploratory work I would do anyway, even without TDD. I think there's nothing wrong to learn (early) that you have done something the wrong way. Often there are many insights you just don't have at the beginning which lead to refactoring. At least, with TDD you have tests in place to do this refactoring safely and I guess it's not slower to refactor the test and application code than it would be to safely refactor the production code without any tests in place.

Marco
Paul Wallace
Ranch Hand

Joined: Oct 09, 2006
Posts: 40
Hi Marco

Thanks for your response, I think you nailed it when you said it "depend on how you actually practice TDD". I think it is more important to iterate quickly between testing and development that to over engineer the testing up front.

To me, being LEAN means always striving to find the optimal way of working, striking be balance between preparation and getting things done.

Regards

Paul
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Paul Wallace wrote:I think it is more important to iterate quickly between testing and development that to over engineer the testing up front.


But that's exactly what TDD is about - a quick cycle of

* write a test
* make it pass by writing/changing production code
* refactor

One such cycle typically takes not much more than a couple of minutes.


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Marco Ehrentreich
best scout
Bartender

Joined: Mar 07, 2007
Posts: 1282

I think I still need a lot more experience with TDD but from what I've learned so far it only pays off if you keep working the TDD way very disciplined. From my understanding this should effectively avoid over-engineering tests and refactoring. I absolutely agree with you that you have to find a balance, but in my opinion this doesn't conflict with TDD if you do it correctly. Of course that's easier said than done, especially for someone new to TDD.

Marco
Jelle Klap
Bartender

Joined: Mar 10, 2008
Posts: 1794
    
    7

Paul Wallace wrote:Hi Marco

Thanks for your response, I think you nailed it when you said it "depend on how you actually practice TDD". I think it is more important to iterate quickly between testing and development that to over engineer the testing up front.

To me, being LEAN means always striving to find the optimal way of working, striking be balance between preparation and getting things done.

Regards

Paul


In my opinion TDD will actually help you build lean software. If you decompose your requirements properly you'll most likely end up with a list of task that each cover a tiny amount of the behaviour and functionality of the system as a whole.
Completing those tasks by first writing tests that cover the expected behaviour / functionality for those task will help you implement that functionality as lean as possible, after all, you'll only be writing just enough production code to get those tests to pass. Keeping things simple and not writing unnecessary code or blowing up an interface with methods that will never be used anyway. In that respect, TDD helps you with lean design of components also. TDD or not, the need to refactor and redesign code is almost always an unavoidable fact of developing new software - in fact it's an integral part of TDD's test-code-refactor approach. If you practice TDD properly you can do so with relative confidence that if you break something somewhere during that refactor / redesign process, your tests will tell you - like working with a safetynet.


Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.
Mary Poppendieck
author
Ranch Hand

Joined: Oct 04, 2006
Posts: 62
If you consider all kinds of software, including embedded software, the mechanism by which you know you are coding the right thing will vary. But what you don't want to see is that after the code is all written, a testing team comes along and re-interprets the specification in a different way than the development team, and then finds lots of problems (of course). You need to know what you are trying to accomplish when you are writing code, you don't want to discover later that what you thought you were supposed to do was wrongly interpreted (by you).

I remember when I was writing process control code that I have a very clear idea of what was necessary to control a process. I often wrote test frameworks to be sure that when I coded, I got it right, but probably not at the detailed level advocated by some implementations of TDD. I did more like what Paul said:

- write the minimum tests required to allow you to develop your solution
...
- iterate until you have enough test coverage to verify your solution.


TDD cannot be an end in itself. The goal is to "Build Quality In" rather than test it in later. The code should always do the right thing, and moreover, it should always be easy to change, since this seems to be a more or less universal requirement of software. There are many ways to do this. In fact, a case can be made that when we discover how to do this without writing quite so many tests, progress will have been made.


Mary Poppendieck
Author of Lean Software Development, Implementing Lean Software Development, and Leading Lean Software Development
Jeanne Boyarsky
author & internet detective
Marshal

Joined: May 26, 2003
Posts: 30789
    
157

Paul,
What if the unit tests were at an API level? Suppose you are trying to write a method that calculates prime numbers (or something more complex.) You would test:
  • assertTrue(isPrime(2));
  • assertTrue(isPrime(3));
  • assertFalse(isPrime(4));
  • assertTrue(isPrime(5));

  • etc

    The tests don't change with the implementation.


    [Blog] [JavaRanch FAQ] [How To Ask Questions The Smart Way] [Book Promos]
    Blogging on Certs: SCEA Part 1, Part 2 & 3, Core Spring 3, OCAJP, OCPJP beta, TOGAF part 1 and part 2
    Paul Wallace
    Ranch Hand

    Joined: Oct 09, 2006
    Posts: 40
    Hi Jeanne

    I see your example as an atomic operation, I was thinking on more compound operations that could have different solutions and have more potential for change on the api itself.

    However, to play devil's advocate. What if you realize, to be more complete, the isPrime() API had to change to take a radix to interpret the number system being used. Lets say the change to the api would be:

    boolean isPrime(int value, int radix)

    If you had written an exhaustive set of tests, you have more test refactoring to do that I would have if I'd only written the essential tests.

    Obviously I am really stretching the example to make my point. And my point is not that unit testing or TDD are wrong, on the contrary, it's that the emphasis should be on quick iteration of the write test - code - execute -refactor cycle in order to be as LEAN as possible.

    Perhaps to summarize, to be LEAN when practicing TDD the emphasis should be on iteration, not completeness of test coverage at the start of development.

    Many will say this point is obvious, I've seen otherwise.

    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Paul Wallace wrote:What if you realize, to be more complete, the isPrime() API had to change to take a radix to interpret the number system being used. Lets say the change to the api would be:

    boolean isPrime(int value, int radix)

    If you had written an exhaustive set of tests, you have more test refactoring to do that I would have if I'd only written the essential tests.


    First, you had only more refactoring to do because you accepted duplication in your tests. If you had rigorously followed the refactoring step of TDD, you would quickly have come up with an

    assertIsPrime(int)

    method or similar. And then, the change only would have been in one single place.

    With other words: writing unit tests that are easy to adapt to change is a skill that needs to be learned. But it's essentially the same skill that you need to learn anyway to make your production code malleable.

    But even if you didn't - all you need to do is introduce the new method, implement the all method as assertIsPrime(number, 10), and do an automated inline method refactoring, and all your tests still work. Not a problem at all.


    Obviously I am really stretching the example to make my point. And my point is not that unit testing or TDD are wrong, on the contrary, it's that the emphasis should be on quick iteration of the write test - code - execute -refactor cycle in order to be as LEAN as possible.

    Perhaps to summarize, to be LEAN when practicing TDD the emphasis should be on iteration, not completeness of test coverage at the start of development.

    Many will say this point is obvious, I've seen otherwise.


    If you've seen otherwise, those were occasions where you actually haven't seen TDD. So with other words what you are saying is that when practicing TDD you should actually practice TDD as written. I couldn't agree more!
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Unit Testing is not LEAN