I'm unclear how TDD, the methodology, handles the following case. Suppose I want to implement the mergesort algorithm, in Python. I begin by writing
assert mergesort([]) === []
and the test fails with
NameError: name 'mergesort' is not defined
I then add
def mergesort(a):
return []
and my test passes. Next I add
assert mergesort[5] == 5
and my test fails with
AssertionError
which I make pass with
def mergesort(a):
if not a:
return []
else:
return a
Next, I add
assert mergesort([10, 30, 20]) == [10, 20, 30]
and I now have to try to make this pass. I "know" the mergesort algorithm so I write:
def mergesort(a):
if not a:
return []
else:
left, right = a[:len(a)//2], a[len(a)//2:]
return merge(mergesort(left)), mergesort(right))
And this fails with
NameError: name 'merge' is not defined
Now here's the question. How can I run off and start implementing merge using TDD? It seems like I can't because I have this "hanging" unfulfilled, failing test for mergesort, which won't pass until merge is finished! If this test hangs around, I can never really do TDD because I won't be "green" during my TDD iterations constructing merge.
It seems like I am stuck with the following three ugly scenarios, and would like to know (1) which one of these does the TDD community prefer, or (2) is there another approach I am missing? I've watched several Uncle Bob TDD walkthroughs and don't recall seeing a case like this before!
Here are the 3 cases:
- Implement merge in a different directory with a different test suite.
- Don't worry about being green when developing the helper function, just manually keep track of which tests you really want to pass.
- Comment out (GASP!) or delete the lines in
mergesortthat callmerge; then after gettingmergeto work, put them back in.
These all look silly to me (or am I looking at this wrong?). Does anyone know the preferred approach?
mergesortisn't a use case; it is an implementation of a use case (the actual use case being sorting), and a very well-defined one at that. You should be able to take the definition ofmergesortand produce a very well-defined and specific set of unit tests from which you can derive your actual implementation. – Robert Harvey Nov 09 '16 at 19:20merge, the entire complex 6-10 line function, is just a part of making the lastmergesorttest pass? Or if I wanted to use TDD on it, I do it off to the side? Did I get that right? Is it a pitch for option 1? Also, I can easily write a test set, but I'm trying to follow the three rules. This is part of an experiment to see how granular TDD can be in certain cases. – Ray Toal Nov 09 '16 at 19:26mergesort, since it's already a very well-defined algorithm, this discovery process is not required, and it then becomes a matter of mapping what you already know to be the design to a series of unit tests. Presumably, your top level test asserts that your method under test accepts an unsorted collection and returns a sorted one... – Robert Harvey Nov 09 '16 at 19:30mergesort. If you're looking for the "right" way to do this, there isn't one, other than to be accurate about your mapping of themergesortalgorithm to a series of unit tests; i.e. they should reflect what amergesortactually does. – Robert Harvey Nov 09 '16 at 19:30mergesortdesign to emerge naturally from red-green-refactor, that won't happen unless you guide the process based on your existing knowledge ofmergesort. – Robert Harvey Nov 09 '16 at 19:36mergesortis known so you shouldn't pretend you are not aware of it. But do know TDD is not particularly well-suited to algorithm discovery. If you were trying to actually derive a new algorithm, TDD is not the best way to go about it. – Andres F. Nov 09 '16 at 19:56mergemust be invented only on "refactoring" stage. If you see thatmergemethod can be introduced for passing test ofmergesortyou first make your tests pass withoutmergemethod. Then refactor your implementation by introducingmergemethod. – Fabio Nov 19 '16 at 16:49