15

I wrote this class that does a few things (perhaps this is a violation of the Single Responsibility Principle). I realize now that some other part of the project needs a piece of that logic and the way I'm going to expose it is to extract a class out of my original System Under Test.

I anticipate being able to do this without having to change any test code, but when I finish, you could argue that the test isn't a unit test anymore. It'll be testing the original class and the class I've extracted. In other words, I'll have one test case, but two systems under test.

Am I supposed to refactor my test code after I'm done? IE: Create an ExtractedClassTest and move all the relevant tests from OriginalClassTest into it? This seems like it could be a little risky: I may lose some coverage in the process, it may not be as simple as moving a test and I'd end up rewriting some test code that I know used to work but may not anymore, etc.

On the other hand, if I leave the OriginalClassTest as-is, I can see this being a test maintenance issue. It'll be a little confusing to find where the ExtractedClass's tests are. Your first impression will be that it doesn't exist. Over time with lots of production code refactorings, this could become a serious issue.

I'm new to TDD so I'd like an expert's advice. Thanks!

2 Answers 2

7

For the duration of the development, have both. Keep the old tests as assurance that you haven't broken anything, write new tests (from scratch) to help you design the classes as they should be.

At the end, run through and remove anything that's defunct in the old tests. Be careful in this analysis; don't remove something because you think it should be defunct. Demonstrate to yourself (or someone else, or a rubber duck) why it isn't needed any more. Break the test and make sure that another test breaks with it.

Anything that's left in the old tests should be taken on a case-by-case basis, but mostly they should be rewritten into the new structure.

Because you're right, you don't want to get left with a maintenance nightmare. But you don't want less path-coverage than you had before.

4
  • 1
    I just did this and I've got to say it's pretty demotivating. Even though my changes were straight forward, it took about 2 hours to make sure I refactored my tests correctly and I still have the same coverage. It became obvious that I should add a few extra tests to the new test just to make sure I was checking things. I feel it would have been more efficient to extract the class and leave two systems under test. Does this amount of work suggest I wrote the tests poorly? Commented Feb 14, 2013 at 22:26
  • 2
    @tieTYT: Hard to answer that without sitting there watching you. Sometimes TDD does seem like more work than it's worth. Other times, you're reminded why you bothered. And other times, it's you that's making it harder. Learning to tell the difference is a big part of getting good at TDD.
    – pdr
    Commented Feb 14, 2013 at 22:48
  • Do you think it's a possibility that in this case I shouldn't have refactored my tests or do you think that's unlikely? Commented Feb 15, 2013 at 0:12
  • 2
    @tieTYT: Unlikely, yes. Impossible, no.
    – pdr
    Commented Feb 15, 2013 at 0:28
7

After watching this amazing talk "Ian Cooper: TDD, where did it all go wrong", I'm going to disagree with @pdr. I think you should only keep the original tests. Your ability to refactor your system under test without breaking, writing or changing any tests is the whole purpose of writing tests in the first place.

If I were to test the extracted class, I'd be testing the implementation rather than the behavior. As a result, my code would be more difficult to refactor in the future: These new tests would likely fail even if the behavior still worked.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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