Unit Testing – How to Write Unit Tests for Legacy Code

legacylegacy codemockingtestingunit testing

Forward

I've read a lot of things before asking this question, including many relevant
questions right here on SE:

However, I can't help but feel that the itch hasn't been scratched yet after
reading for help.


TL;DR

How do I write unit tests for legacy code that I can't run, simulate,
read about, or easily understand? What regression tests are useful to a
component that presumably works as intended?


The Whole Picture

I'm a returning summer intern again as I'm transitioning into grad school. My
tasking involves these requirements:

  1. For a particular product, evaluate whether our software team can upgrade
    their IDE and JUnit version without losing compatibility with their existing
    projects.
  2. Develop unit tests for some component in the existing Java code (it's largely
    not Java). We want to convince the software team that unit testing and TDD are
    invaluable tools that they should be using. (There's currently 0% code coverage.)
  3. Somehow, end the days of cowboy coding for a critical system.

After obtaining a copy of the source code, I tried to build and run it, so that
I might understand what this product does and how it works. I couldn't. I asked
my supervisors how I do, and I was issued a new standalone machine capable of
building it, including the build scripts that actually do. That didn't work
either because as they should've expected, their production code only runs on the embedded system it's designed for. However, they have a simulator for this
purpose, so they obtained the simulator and put it on this machine for me. The
simulator didn't work either. Instead, I finally received a printout of a GUI
for a particular screen. They also don't have code comments anywhere within the
700,000+ Java LOC, making it even harder to grasp. Furthermore, there were
issues evaluating whether or not their projects were compatible with newer IDEs.
Particularly, their code didn't load properly into the very IDE version they use.

My inventory is looking like this:

  • NetBeans 8, 9, 10, 11
  • JUnit 4, 5
  • Their source code for a particular product (includes 700,000+ Java LOC)
  • Virtually no code comments (occasionally a signature)
  • No existing tests
  • A physical photo of a GUI window
  • A software design document (109 p.) that doesn't discuss the component in the picture

I at least have enough to theoretically write tests that can execute. So, I
tried a basic unit test on this said component. However, I couldn't initialize
the objects that it had as dependencies, which included models, managers, and DB
connections. I don't have much JUnit experience beyond basic unit testing, so
follow me to the next section.


What I've Learned From My Reading

  1. Mocking: If I write a unit test, it likely needs to have mock variables for
    production dependencies that I can't easily initialize in setUp.
  2. Everyone here liberally suggests the book "Working Effectively with Legacy
    Code" by Michael Feathers.
  3. Regression tests are probably a good place to start. I don't think I have
    enough weaponry to attempt integration testing, and regression tests would
    provide more instant gratification to our software team. However, I don't have
    access to their known bugs; but, I could possibly ask.

And now an attempt to articulate the uncertainty I still have as a question.
Essentially, I don't understand the how part of writing these tests. Assuming
I don't receive any further guidance from my supervisors (likely), it's in my
ballpark to not only learn what this component does but to decide what tests are
actually useful as regression tests.

As professionals who've worked with projects like this longer than I have, can
you offer any guidance on how to write unit tests in this kind of situation?

Best Answer

To a first approximation, the stakeholders of a test suite are the code developers/maintainers. You're going to need some of their time. Insist on this.

Ask them about problems they're facing.
Ask them about bugs they've fixed recently (in the past couple of years, assuming this is a long slow project).

I get the impression that you're not expecting them to be amiable to your work; maybe you're right. But I don't think you can build anything useful without their help.

They're going to hold your hand through writing the first test. Maybe you'll be dragging them, but you'll be holding hands either way.

Once you have one test, hopefully it'll be clearer how to write the second. If you've managed to build any kind of rapport, it will certainly be clearer.