The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Does Refactoring Make Unit Tests Irrelevant?

I like the idea of using unit tests to help ensure that adding new code or refactoring old code doesn't introduce bugs.

I want to start using the idea, but I can see a problem...

When I'm refactoring, I'll probably be rearranging the "units" of software.  If my unit tests refer to the old "units", haven't I just broken all of my tests?  So I now have to write new unit tests for my refactored code?  New code to test new code - how does that help prevent bugs?

What am I missing here?

PS. I'm not asking if unit testing is a good idea.
Brendon Send private email
Sunday, December 18, 2005
Refactoring as I understand it is rebuilding code within the same unit.  Such as rewriting a search function from one algorithm to another that at least in theory is more efficient based on the needs of your application.

However if you ARE changing how units are organized it would have a good chance of forcing a rewrite on unit tests.  But then again being forced to acknowledge such a fundemental system change is important as it tends to imply you may be about to break other parts of your application that assume a piece of code is in one particular file/class/etc.
Patrick Sullivan
Sunday, December 18, 2005
You'll be writing and fixing tests as you refactor so there is no time when you are writing all new tests or fixing all old tests. You are implementing small chunks at a time and creating/fixing unit tests as you go.
son of parnas
Sunday, December 18, 2005
Refactoring requires unit tests. If your code changes breaks the test, then the test has done its job to tell you you have not refactored correctly.
Art Wilkins
Monday, December 19, 2005
+1 Art

Refactoring makes Unit Tests ESSENTIAL.

Monday, December 19, 2005
If you have to provide some backwards compatibility to users/client systems, you may need *new* Unit Tests to reflect the new pieces of functionality, but you'll also need Unit Tests to test how they're using the code.

This can lead to a series of Adapter Patterns being used.  While it's not exactly efficient, it provides some backwards compaitibility.
KC Send private email
Monday, December 19, 2005
It sounds like your problem is that you don't want to spend a lot of time writing tests against private or what should be private methods/functions only to refactor them significantly.  It will delay actual coding quite significantly.

I suggest figuring out your future public interfaces, writing stubs for that which simply call the appropriate internal functions for now, and writing your tests against that public interface.  That way you have 1 point of change rather than many.  As you refactor the internal mechanisms your tests will break, telling you that you need to change your public methods to account for it. 

You're still testing input > ouput, but avoid testing everything in the middle directly.  It isn't necessarily the best way, but you can make sure you aren't causing problems while you make sizable changes. 

Note that any areas with complicated logic that appear to be working around an edge case should be noted and tested before refactoring.
Lou Send private email
Monday, December 19, 2005
> I suggest figuring out your future public interfaces,

Not very TDDish.

You should test whatever it takes for you to know your code works.

If you find changing a class breaks a lot of other things outside that class then that's a clue your code needs to less coupling and more cohesion. Breaking tests for a particular class should not be a big deal.
son of parnas
Monday, December 19, 2005
The big problem in software is when you make a seemingly insignificant change in Module A, that breaks behavior in Module B.  This is a problem because there may be no indication at the time you changed Module A that it was in fact breaking Module B, nor any way you as a programmer could anticipate that changing Module A might break Module B.

"Normally" (in the days without automated unit testing) this would require re-running a suite of "regression tests" against ALL your code, to insure there were no un-intended side effects of changing Module A.

With automated unit tests, you can re-run the regression test against your entire system in a reasonably short period of time, and detect that Module B was broken, or guarantee that Module B was NOT broken, by your change to Module A.

Now, changing Module A may require you to change Module A's unit tests, yes.  But that's STILL simpler than just ignoring what could have happened to Module B in the process, only to have it bite you later.
Monday, December 19, 2005
Thanks for the responses, it's made things clearer.

I guess my take now is that usually unit tests will be OK, but occasionally I may have to change the public interfaces of a class or two, which may break a small number of unit tests.

You're right, low coupling will minimise the detrimental effects in this case. Testing input > output, rather than all the stuff in the middle will help too.

Also, I'll always be doing a little bit at a time, so the "big change" issue may never arise.

BTW, I was also assuming that it's not going to be perfect or complete the first time, and that changing/adding/removing public methods etc would be necessary (in some cases, but I guess, not very often).

Thanks once again.
Brendon Send private email
Monday, December 19, 2005
Refactoring includes unit and integration test cases.

System test cases should not change (assuming strict refactoring without any system interface redesign).
Dino Send private email
Tuesday, December 20, 2005
Let me rephrase your question:

Does [Buzzword #1] make [Buzzword #2] irrelevant?

With that in mind, the answer is: probably no.

Have an excellent day, everyone.
pds Send private email
Wednesday, December 21, 2005

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
Powered by FogBugz