• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Unit Testing is not LEAN

 
Ranch Hand
Posts: 48
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
best scout
Posts: 1294
Scala IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 48
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

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.
 
Marco Ehrentreich
best scout
Posts: 1294
Scala IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
Bartender
Posts: 1952
7
Eclipse IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

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.
 
author
Posts: 62
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.
 
author & internet detective
Posts: 41860
908
Eclipse IDE VI Editor Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.
     
    Paul Wallace
    Ranch Hand
    Posts: 48
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    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
    Posts: 14112
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    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!
     
    reply
      Bookmark Topic Watch Topic
    • New Topic