Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I am experimenting with test-driven development, and I found that I often come to a following situation:

  1. I write tests for some functionality X. Those tests fail.
  2. While trying to implement X, I see that I need to implement some feature Y in a lower layer of my code. So...
  3. I write tests for Y. Now both tests for X and Y fail.

Once I had 4 features in different layers of code being worked on at the same time, and I was losing my focus on what I am actually doing (too many tests failing at the same time).

I think I could solve this by putting more effort into planning my tasks even before I start writing tests. But in some cases I didn't know that I will need to go deeper, because e.g. I didn't know the API of lower layer very well.

What should I do in such cases? Does TDD have any recommendations?

share|improve this question
add comment

5 Answers

up vote 9 down vote accepted

The good thing is that you realize your code under test needs assistance. Rather than implementing it right away, create an interface and use mocks to make sure your tests are tageting the correct code. After you get those tests passing, you can then move on to implementing the code it relies on.

share|improve this answer
    
My tests usually do not have knowledge about what should a method do internally (f.e. what lower-level API to call). Should I just adjust the tests to mock whatever I need in the tested code? –  liori Jun 25 '11 at 15:18
2  
Similarily, your tested classes should not care what 'lower layers' do. Use mocks/stubs in place of actual classes/objects. This might require a bit more effort in design, but results in code that's less coupled and easier to reuse. –  Mchl Jun 25 '11 at 15:52
1  
Are you using dependency injection? This is how you can easily separate lower level concerns from higher level classes. Your class under test has a constructor with parameters for its dependencies (as interfaces) in your test you create mocks for the interfaces. Basically you're pretending that you've already implemented the lower level services. –  Mike Brown Jun 25 '11 at 16:09
    
@Mike Brown, yes, I do. I know I can create mock objects. But then in my test for feature X I have to know what part of dependencies of X I need to mock. I feel that this is part of implementation details, which should not be part of tests--otherwise I might need to change tests while refactoring the implementation. Should I worry about that? –  liori Jun 25 '11 at 16:20
1  
Not at all...the tests should reflect the assumptions of the system under test. It also helps you expose what you need from the services the system relies on. I used to agree with you on this matter but I compare it to how I came to understand recursive programming. First you write the code assuming that you have a function that does what you want. Then you write the code that does what you want. –  Mike Brown Jun 25 '11 at 17:38
show 1 more comment

Stubs and mocks can be used to simulate the functionality that is not being modified/implemented yet. They can also help you to resolve the dependencies that causes this kind of 'chain reaction'.

On the other hand, maybe keeping only one (failing) test that drive the very next change is the best approach.

Other tests that target the code that relies on new functionality can be termporarily disabled as they are not really relevant at this point ie. in your case, disable tests for X until you implementing Y etc.

That way you can keep your focus on the next change only which is what you want, I think.

share|improve this answer
    
Ha, I looked for a feature to turn off a test during a test run inside my IDE, and haven't found one. Now I found that python's unittest already has test skipping. This might be enough for me. –  liori Jun 25 '11 at 15:20
    
We use google test C++ framework - and it has an option to disable tests. Disabled tests are not executed but compiled - the moment you need them - they are there ready to run (in addition you can 'force execution' of disabled tests - kind of 'run-time enable') - excellent feature... –  ratkok Jun 25 '11 at 16:00
add comment

Stop

Offhand it looks like there may be two separate issues here:

  1. you forgot some stories and test scenarios, and didn't discover them until you started working on a particular test scenario, and/or

  2. you're actually doing unit testing, and not TDD feature testing

For #1, stop, go back, and update the stories and test scenarios, then start over with a different scenario.

For #2, stop, and remember that you're testing features, not units, so employ mocks to gloss over other interfaces and/or implement more code to make the test pass without adding new test scenarios. This assumes that you are not missing test scenarios, but are instead - and this is really common - conflating unit testing and TDD.

share|improve this answer
    
I really like your answer, it does a better job of explaining what is really going on. –  maple_shaft Jun 26 '11 at 12:04
    
... With that being said I don't know a PM in the world who won't completely lose his/her mind at the phrase, "STOP, we need to backtrack". They will try everything short of sacrificing their first born at the altar to keep the project moving forward, technical debt and incomplete unit tests be damned. I guess you can't blame them when their only metric at an organization is getting the project done on time. Some orgs just value time over quality and this is why I probably never seen TDD work successfully at these types of organizations, which is unfortunately MOST of them IMO. –  maple_shaft Jun 26 '11 at 12:04
    
@maple_shaft: the amount of time that you stop to regroup may just be a few hours - unless your process is way, way off base, in which case stopping for a few days to get it back on track will make it far more likely that the project will succeed. There's not point in going full steam ahead down the wrong track! –  Steven A. Lowe Jun 26 '11 at 18:49
add comment

This is a great question and a HUGE frustration for me as well with TDD. I feel like TDD lacks in this scenario where you just have no way of knowing what lower level components or features you will need until you start developing.

Personally I found that TDD only works if you know exactly what you need to do and what you need to call to perform a feature. Developers don't always know everything before we start so I have found that the best way for myself to mitigate the very situation you describe:

Prototype

When I make simple prototype apps to explore and discover methods and approaches to a technical problem then I discover a lot of the leg work and get that research out of the way before I start. Designing and estimating become a lot easier as well.

If the prototype has to be so involved that it becomes the application then I urge you to not do the lazy thing however and build unit tests for your prototype after the fact.

You should know more about the lower level API at that point and be able to successfully mock the lower level API in your higher level components.

share|improve this answer
    
So you're actually suggesting to get more information for the planning phase by performing some exploratory coding in an informal (=not going by some formalized methodology) way. And then assume that it will give enough information to plan the real code. Am I right? –  liori Jun 25 '11 at 16:27
    
Why do you assume that prototyping is an informal process? Every estimate should account for prototyping and project schedules should account for it as well as a necessary development task. I view it the same as Design or Code-Review. On that note it IS formalized and should be accounted for, even more on tasks with a lot of unknowns. Without prototyping and the ability to perform Proof-of-Concept, then pursuing TDD just assumes that developers know EVERYTHING about ANYTHING with ALL features. The real world doesn't work that way and I don't care how intelligent or experienced you are. –  maple_shaft Jun 25 '11 at 16:35
    
By "informal way" I didn't mean that time for prototyping should not be accounted for, but that while you do prototypes, you don't follow TDD or any other code methodology. –  liori Jun 25 '11 at 16:40
    
TDD is a methodology for Unit Testing and Development. Would it make sense to do TDD for Code Review? Does TDD make sense for Design, writing Technical Specifications or Whiteboarding? Prototyping is a task of itself, an exploratory type of development for research, proof of concept, and education. –  maple_shaft Jun 25 '11 at 18:00
1  
TDD makes perfect sense for prototyping. It allows you to rapidly expose the things your whatever-it-is (object, function, API, entire program) in the form of a repeatable, executable set of requirements. Do yourself a favour and read Growing Object Oriented Software Guided by Tests; it takes you step by step through building an entire application (including integration) in a test-first manner. –  Frank Shearar Jun 26 '11 at 11:40
show 3 more comments

It depends what kind of tests your writing while doing TDD.

The classic model is to write unit tests and make use of mocks or stubs to decouple the test from the other "units" of code.

There are many other alternative model such as ATDD where the test a full stack, or almost full stack test. In this particular case your writing tests that assert required program behavior not a single unit of code so you wouldn't be writing other tests. You would get the implement the roundtrip to satisfy the test. You then add other tests for other features/behaviors.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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