
Legacy Code Testing Interview Questions
Is there no way legacy code can own you?


Can you describe the sprout method in regard to refactoring legacy code?
In short, the method is about extracting a piece of code into a separate class or public method. It allows you to work on a change in isolation without the fear of breaking other code. It also makes introducing code to test harness easy thanks to extraction. It is a flag example which follows the Single Responsibility Rule.

What are the reasons we change our software? For which one you think it is the hardest to implement automated tests?
- Adding a new feature
- Fixing a bug
- Improving the design
- Optimizing resource usage
The first two are relatively straightforward when it comes to introducing automated tests. At least compared to the other two. Each bug can be treated as a feature on top of that and vice-versa.
What developers generally detest is improving the design as it is relatively easy to loose the existing behaviour and introduce a bunch of bugs. You also need to bring your A game once this task has been assigned to you. It almost always a challenge.

Is TDD adequate for legacy code testing?
I am sure you have heard that you should cover the public method that needs a change with a full set of unit tests before even touching it.
This is sort of a TDD for the legacy code testing.
That might be true if the method is relatively small. That happens very rarely though in a legacy codebase.
The safest way, where you do not need to waste a week covering all the possible logical paths with tests, is to take advantage of the Sprout Method / Class.
You basically extract the smallest part of the public method possible into a separate class.
You cover that with tests, and then you could start a few TDD cycles to get the actual change.
This is sort of a TDD for the legacy code testing.
That might be true if the method is relatively small. That happens very rarely though in a legacy codebase.
The safest way, where you do not need to waste a week covering all the possible logical paths with tests, is to take advantage of the Sprout Method / Class.
You basically extract the smallest part of the public method possible into a separate class.
You cover that with tests, and then you could start a few TDD cycles to get the actual change.

How can we follow the boy scout rule in regard to legacy code testing?
The main idea behind this rule is to make the proximity of you change better.
After writing tests, try to add missing comments on interfaces, raname variables etc.
Also as we are dealing with legacy stuff, try add some additional tests to the proximity of your change.
Make this a habit and a change in software quality will come sooner than you think.
After writing tests, try to add missing comments on interfaces, raname variables etc.
Also as we are dealing with legacy stuff, try add some additional tests to the proximity of your change.
Make this a habit and a change in software quality will come sooner than you think.

How would you approach a change in a large legacy method?
A mixture of refactoring and automated testing is in general the only way.
The way you refactor is up to you. The key here is to extract small enough chunks of code so that they can be easily tested. Spout method is an excellent choice here.
Then the change can be applied on one or many of the chunks and cemented with even more tests.
When it comes to refactoring there is a choice between some automated refactoring tool offered by most modern IDE's or manual refactoring. The second one is of course more challenging but the lessons we take from that approach are priceless.
The way you refactor is up to you. The key here is to extract small enough chunks of code so that they can be easily tested. Spout method is an excellent choice here.
Then the change can be applied on one or many of the chunks and cemented with even more tests.
When it comes to refactoring there is a choice between some automated refactoring tool offered by most modern IDE's or manual refactoring. The second one is of course more challenging but the lessons we take from that approach are priceless.

Can you describe the wrap method in regard to refactoring legacy code?
It is used when:
Having that said, what we do next is to create a new method that calls internally the original method.
Then using TDD we apply the change in the wrap method without touching the original one.
- The method is too complex for it to be unit tested efficiently.
- The change to be applied goes at the beginning or the end of a certain feature.
Having that said, what we do next is to create a new method that calls internally the original method.
Then using TDD we apply the change in the wrap method without touching the original one.

A lot of projects rely heavily on a certain library. How would you implement the usage so that it is maintainable and testable?
Here are a few points to follow in regard to framework methods handling:
- The code that directly interacts with 3rd party libraries should be isolated and treated as the only point of entry for the rest of the code.
- It should be thoroughly tested. We should not mind going for 100% coverage here. It will most likely be the code of our app and it should be flawless. That amount of coverage gives us also freedom to refactor the code as we please to maximize its readability and maintainability.
- We should try to add some load testing on top of plain unit tests. How does the system behave when hundreds of threads call a single 3rd party library?

What do you understand by the term of characterization tests?
Characterization tests are done on a piece of code which behaviour we want to preserve.
The only reason for the test is to help us figure out how the code works.
An implicit benefit, once we find a way the test to pass is the increase of coverage.
The only reason for the test is to help us figure out how the code works.
An implicit benefit, once we find a way the test to pass is the increase of coverage.

Can you give the definition of a seam?
A seam is a place in your code (a hook) thanks to which you can change the behaviour without the need to edit to code in place.
The behaviour can be altered in a way that there is no need to break existing dependencies. This is very important in regard to legacy testing.
The behaviour can be altered in a way that there is no need to break existing dependencies. This is very important in regard to legacy testing.

Name a few dependency-breaking techniques.
- Using a mocking framework such as Mockito.
- Breaking the code into smaller, specialized classes.
- Using seams / hooks where it is highly likely that the behaviour may change or be dependent on the environment.