Using Characterization Tests When Working With Legacy Code

Every software engineer has worked with legacy code in some way. Knowing how to work in different environments is essential, especially with legacy.

Let's reflect on the following definition of legacy code from the book Working Effectively With Legacy Code by Michael C. Feathers:

"In the industry, legacy code is often used as a slang term for difficult-to- change code that we don’t understand. [1]"

But the author goes one step further and says:

"To me, legacy code is simply code without tests. (...) Code without tests is bad code. (...) Without them [tests], we really don’t know if our code is getting better or worse. [1]"

The author also introduced a new concept called characterization tests.

"A characterization test is a test that characterizes the actual behavior of a piece of code. [2]"

By doing these tests, you will lay down what each piece of code does.

In the book, the author gives instructions on how to implement characterization tests [2]:

  1. Pick the code you want to test.
  2. Implement a test with an assertion that you know it will fail.
  3. When the test fails, you will get the correct answer for it.
  4. Change the assertion of the test to contain the correct value.
  5. Rerun the test.

These might sound counter-productive. You are relying on what the code is telling you to create tests.

You will blindly throw random values at your test to make it fail.

It is important to relay here that the code we used wasn't good initially, or worse, you are not sure what it's doing.

How can you debug code that you're not confident of its behavior?

By laying this foundation, you are adding documentation of your code somewhere. You will let other people know and understand what they can or cannot expect from the method.

Example

To avoid introducing code, let's use the example that my aunt used to do to me and my brother when we were kids. She usually used the characterization test approach when she wanted to know a secret we had.

Clearly, my aunt was already ahead of her time in using this methodology.

Conclusion

Characterization tests might sound counterproductive. You are relying on the output of your method to make a test and not using what you expect your code to do.

By doing this, you're laying a foundation that will improve the readability for other people in the future, and you're also guaranteeing that a piece of code behaves like you're expecting it.

💡
If you enjoyed this article, consider following me on LinkedInGitHub, and X.

Thank you for reading.

References

  1. Working Effectively With Legacy Code: Preface by Michael C. Feathers page 17
  2. Working Effectively With Legacy Code: Characterization Tests by Michael C. Feathers page 220

Subscribe to Coding With Vera

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
[email protected]
Subscribe