Forward
I've read a lot of things before asking this question, including many relevant questions right here on SE:
- (Software Engineering SE) Writing tests for code whose purpose I don't understand
- (Software Engineering SE) Unit testing newbie team needs to unit test
- (Software Engineering SE) Best practices for retrofitting legacy code with automated tests
- (Software Engineering SE) How to unit test large legacy systems?
- (Blog post) How to mock up your Unit Test environment
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:
- For a particular product, evaluate whether our software team can upgrade their IDE and JUnit version without losing compatibility with their existing projects.
- 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.)
- 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
- 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
. - Everyone here liberally suggests the book "Working Effectively with Legacy Code" by Michael Feathers.
- 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?
How do I write unit tests for legacy code that I can't build, run, simulate, read about, or otherwise understand?
-- You can't. You have to at least know what the expected output is for a given input.