Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refactoring and Test Driven Development

I'm Currently reading two excellent books "Working Effectively with Legacy Code" and "Clean Code".

They are making me think about the way I write and work with code in completely new ways but one theme that is common among them is test driven development and the idea of smothering everything with tests and having tests in place before you make a change or implement a new piece of functionality.

This has led to two questions:

Question 1: If I am working with legacy code. According to the books I should put tests in place to ensure I'm not breaking anything. Consider that I have a method 500 lines long. I would assume I'll have a set of equivalent testing methods to test that method. When I split this function up, do I create new tests for each new method/class that results?

According to "Clean Code" any test that takes longer than 1/10th of a second is a test that takes too long. Trying to test a 500 long line legacy method that goes to databases and does god knows what else could well take longer than 1/10th of a second. While I understand you need to break dependencies what I'm having trouble with is the initial test creation.

Question 2: What happens when the code is re-factored so much that structurally it no longer resembles the original code (new parameters added/removed to methods etc). It would follow that the tests will need re-factoring also? In that case you could potentially altering the functionality of the system while the allowing the tests to keep passing? Is re-factoring tests an appropriate thing to do in this circumstance?

While its ok to plod on with assumptions I was wondering whether there are any thoughts/suggestions on such matters from a collective experience.

like image 722
K2J Avatar asked Mar 18 '09 10:03

K2J


People also ask

What is TDD and refactoring?

Refactoring is a disciplined design skill to improve the structure of code without changing its external behavior. And refactoring is part of the TDD cycle. Thus, in this course you will learn the various “code smells” and the refactorings to clean them up.

What are the 3 stages of TDD?

Test-driven development (TDD) is an approach to software development where you write tests first, then use those tests to drive the design and development of your software application.

Why is refactoring important in TDD?

Create a maintainable codebase The next step required in the TDD process is refactoring, which stands for the optimization of existing code and has the single objective of making it simpler to introduce. Developers can refactor a tiny feature or improvement's code to meet standards if it passes the initial tests.

How would you define refactoring as used in Test-Driven Development?

TDD testing includes refactoring a code i.e. changing/adding some amount of code to the existing code without affecting the behavior of the code. TDD programming when used, the code becomes clearer and simple to understand.


3 Answers

  1. That's the deal when working with legacy code. Legacy meaning a system with no tests and which is tightly coupled. When adding tests for that code, you are effectively adding integration tests. When you refactor and add the more specific test methods that avoid the network calls, etc those would be your unit tests. You want to keep both, just have then separate, that way most of your unit tests will run fast.
  2. You do that in really small steps. You actually switch continually between tests and code, and you are correct, if you change a signature (small step) related tests need to be updated.

Also check my "update 2" on How can I improve my junit tests. It isn't about legacy code and dealing with the coupling it already has, but on how you go about writing logic + tests where external systems are involved i.e. databases, emails, etc.

like image 195
eglasius Avatar answered Oct 09 '22 14:10

eglasius


The 0.1s unit test run time is fairly silly. There's no reason unit tests shouldn't use a network socket, read a large file or other hefty operations if they have to. Yes it's nice if the tests run quickly so you can get on with the main job of writing the application but it's much nicer to end up with the best result at the end and if that means running a unit test that takes 10s then that's what I'd do.

If you're going to refactor the key is to spend as much time as you need to understand the code you are refactoring. One good way of doing that would be to write a few unit tests for it. As you grasp what certain blocks of code are doing you could refactor it and then it's good practice to write tests for each of your new methods as you go.

like image 45
sipsorcery Avatar answered Oct 09 '22 15:10

sipsorcery


    • Yes, create new tests for new methods.

    • I'd see the 1/10 of a second as a goal you should strive for. A slower test is still much better than no test.

  1. Try not to change the code and the test at the same time. Always take small steps.

like image 22
starblue Avatar answered Oct 09 '22 14:10

starblue