I am trying to practice TDD.
My understanding is that TDD should go like this
The problem I have is when writing the implementation or doing the refactoring. I often come to the conclusion that the implementation I just wrote should be delegated to another class.
What should a true TDD'r do at this point?
I'd love to know how other people handle these situations.
Many programmers have tried this technique, failed, and concluded that TDD is not worth the effort it requires. Some programmers think that, in theory, it is a good practice, but that there is never enough time to really use TDD. And others think that it is basically a waste of time.
Test-driven development (TDD) is a software development process relying on software requirements being converted to test cases before software is fully developed, and tracking all software development by repeatedly testing the software against all test cases.
With developer TDD you write a single developer test, sometimes inaccurately referred to as a unit test, and then just enough production code to fulfill that test. The goal of developer TDD is to specify a detailed, executable design for your solution on a JIT basis. Developer TDD is often simply called TDD.
Don't look for a one-to-one relationship between your tests and your classes. If you decide to introduce a new class, let that be a refactoring supported by the original test, and add tests in the appropriate place (where that is depends on the specific case) when you want to add functionality (or to test eventualities you need to cover that you didn't test for yet).
I would add that the main success in TDD is to get into the rhythm of red-green-refactor. When you feel the benefit of that rhythm, you have started to "get" it. That isn't to say you will find it worthwhile in all cases, but until you feel that rhythm you haven't gotten to what its advocates like about it.
And there is usually (especially in architecturally complicated applications, like n-tier applications) some amount of up-front design. Nothing sketched in stone, but enough to give the units a place to go. Of course the architecture may evolve in an agile methodology, but a general idea of the landscape needs to be there if there are multiple layers to the architecture.
EDIT: (In response to the comment). Should the new class get tested in its own right? Not necessarily. It depends if the class develops an importance of its own. When you are unit testing, you are testing a piece of functionality. It isn't an integration test just because there are two classes involved. It becomes an integration test when two units start interacting. The boundary I typically think of is if I have to set up significant state in group-of-classes A to interact with group-of-classes B, and especially if group-of-classes A calls group-of-classes B and what I am interested in testing is how B reacted to A, then I'm looking at an integration test.
The problem I have is that when I arrive at point 6 & 7, at some point in time I invariably come to the conclusion that the implementation I just wrote should be delegated to another class.
Realizing your design would be better with a different class - that's design, and that's the point of TDD. So it's a fine thing, and it shouldn't bother you.
But it's bothering you. So what to do? Recognize that delegating to another class is a refactoring; this is something to be done after step 6, during step 7. Once you're green, refactor to a better design. You've already got the tests for the new class; they're just wired to call the original class. That's perfectly fine. After extracting the class and delegating, if you would be more comfortable having the tests call the extracted class directly: go for it. No harm. If the extracted class starts to get used by other callers, I'd recommend it, and maybe when you start calling it from other classes is a good time to do that (but if it bugs you now, do it now).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With