The heroic adventures of unit testing a legacy application

by Iulia Dormenco & Andreea Nita

December 4th 2019 – It may sound scary, but it’s a happy story, I promise. As developers, we’re all afraid of legacy code and the minute we hear the word we cry in despair. And then you say “innovation in a legacy application? Can’t be done”. Well, bear with us and we’ll tell you the success story that inspired us to believe that no project should be left behind.

Keep in mind, happy stories are not created by being defeatist in the face of hardship, as no success comes from seeing failure before attempt. This is especially true for legacy applications, which tend to come with many more challenges. They require a certain professional attitude that is hard to cultivate, but which can bring many benefits.

The why

As software developers and crafters, we always believe in the good we bring to the world by practicing our job: stable applications that help thousands of people and make their lives easier. As developers involved in a growing community, though, we should and are invested in building not just working software, but also well-crafted software, which would bring value not only to the application, but also to the entire community of professionals. It is with these core values and goals in mind that we went on our journey.

The starting point: around 370 tests, out of which over 80 were failing and a couple were completely ignored. The destination: almost 1000 unit tests and over 300 integration tests.

There’s a valuable lesson that we draw even from before starting on our brave path: software is an ever-changing domain. Often, something that seemed state-of-the-art 5 years ago begins to look quite stale and outdated in our modern day. For a project that has been ongoing for 10 years, as is the case here, we need to keep in mind that it has gone though many stages, from team and business changes, to simply trends and their flow making their mark on the application.

Just remember how we used to do code reviews before git and pull requests: we gathered round the developer’s workstation and went through a whole list of changes, maybe adding to do’s in the code, being more or less thorough and at some point all those changes just got pushed to a trunk branch. And as much as we try to keep up with best practices, it is inevitable that some area of the application will probably get left behind if it does not change often, especially if still works and brings the client value.

It is the desire to perfect our trade with time that made us take on this adventure, and it is with the hope that new minds will keep this set of values alive in the future that we share this story today.

The how

In a beautiful and perfect story, the hero developers would just roll their sleeves, get on their white horse and save the day. In our case, the heroes are seasoned developers that knew they had to assess the problem before hurrying to slay the dragon. So, after carefully studying the beast (fragile tests, long execution times, no asserts or too many asserts) they chose their magic sword: xUnit.NET as the one framework (to rule them all).

The road

In a legend, the journey may be filled with perils, yet our heroes went in prepared. The plan? Clean up and build up. The team systematically went through all of their testing projects, deleted the tests that made no sense (or were too complicated to understand), and rewrote the ones that actually brought value. Sure, they met a couple of roadblocks on the way, yet with great teamwork and constant learning, they didn’t just survive, they thrived. They held constant dev meetings and code reviews where they supported each other along the way, they read the resources and held the trainings they needed in order to build the skills and forge the weapon they needed in the battle. And then they climbed the mountain, to reach the top, where the victory castle held the wonderful prize: 1000 unit tests.

The now

The dragon’s nearly slain, and victory is in sight for our brave knights. Their win may not be the princess, yet it’s close enough. The code coverage is now preferentially on core logic and new functionality, and they win the experience to start fresh new projects and functionalities with tests from the very beginning. And the ultimate win: the heroes now have the confidence they were striving for, that we are both building the right thing and the thing right.

This amazing result did not only give a boost of confidence in the developer’s wings, but it also enabled great things for the project and for the team: Continuous Delivery, more frequent releases and fewer bugs, both during development and after deploying the new features to production.

Yet in the end, the most amazing result is the lessons that we draw from this experience, and which we are willing to share with all of you brave knights embarking on an adventure of their own: first of all, attitude is everything. It may sound cheesy, but it’s true. All that really matters when working on a project is the fact that when faced with your legacy code dragon, you can make a choice: either get frustrated and do nothing or do something to make it better. It’s the decision we make that shapes us as individuals and professionals in the workplace. And secondly but not least, we need to think about what it means to be a professional no matter the context that we find ourselves in as developers. Yes, monsters will show up on our path and the road might seem long and tiresome, yet it is the values we hold strong which will lead us to the treasure.

Share this article