Skip to content
  • There are no suggestions because the search field is empty.

Writing Tests for a Codebase with No Tests

Isn't it ironic when you come across a job description that lists testing skills as part of their job requirements, only to find out after joining the project that they hadn’t implemented any?

Or maybe you’ve built an MVP. You have found product-market fit, but you took on every possible technical debt in the book, including testing debt (of course!), to get there.

So, what do you do?

How can you introduce tests into a codebase with close to zero tests without feeling overwhelmed or hindering product development?

In this article, we’ll discuss how you can start introducing tests into a “testless” codebase in a structured and systematic manner, enabling you to manage your project without hindering product development or delivery.

Let’s dive in.



Start with Features in Development

“Where the hell do I start from?” is probably the first question you would ask yourself when you join a large project with no tests.

So, where do you begin?

Start with features currently in development, then proceed to critical functionalities, starting with the most crucial.

By introducing tests for features currently being developed, you prevent further introduction of test debt into the project, making it easier to maintain the codebase as more features are added.

This way, you can be confident that ongoing development is not adding to your debt.

Next, conduct a critical path analysis to identify the critical areas of the project. The critical areas are those parts of your project that, if broken, would make the project completely unusable by the users. After identifying these critical aspects, walk your way down to the least critical.

By starting with the features in development and moving to critical project features, your testing process will be structured and effective. This will ensure that ongoing development does not add to your technical debt and your codebase is easier to maintain.


Choose — Unit Tests or Integration Tests

Now that you know where to begin, you can turn your focus to integrating the tests. But what tests should you write for your project?

It depends as neither unit nor integration tests can be outrightly considered the best.

The key to making an effective decision is understanding the functionality you're testing and identifying which kind of testing would add the most value.

If your project contains a lot of functionalities that work without external dependencies, unit tests might be the way to go. However, if you’re working with external APIs or you observe that testing functions in isolation don’t provide much confidence in the stability of the feature, integration tests might be more appropriate.

And in other cases, it might be beneficial to utilize a mix of both types of tests.

The key is to analyze your project requirements and aim for a balance.


Choose the Right Tools and Frameworks

After identifying what to test, the next step is selecting your tools. But what makes a tool the right fit?

Choose tools and frameworks that are compatible with your language, setup, team experience, and have strong community support and rich documentation.

For instance, Jest is an excellent choice for a Javascript project and RSpec for Ruby. They both have great community support and rich documentation which can significantly reduce the learning curve and implementation challenges for your team.

Personal tip: Don't aim for tool perfection. No tool is flawless. Choose what fits your current project needs, and switch if your requirements change.


Integrate Tests into your Development Workflow

You can integrate your tools and frameworks into your CI / CD Workflow.

Integrating tests into the development workflow using Continuous Integration (CI) systems provides immediate feedback on code changes and helps detect and fix issues promptly.

You can use CI / CD tools like Jenkins or GitHub Actions to integrate testing into your development workflow to streamline your code review processes, automatically run tests, and verify code functionality.

This not only improves code quality but also fosters a collective responsibility within the team for maintaining a robust test suite.


Save Time with AI

AI tools, such as ChatGPT, have significantly impacted testing processes, streamlining them and saving teams hundreds of hours of testing time.

For example, you could use chatGPT to brainstorm edge cases for your unit and integration tests, ensuring thorough test coverage or use it to generate mock data for more robust tests.

You could also save time writing tests by leveraging AI-powered tools like GitHub Copilot or Amazon Code Whisperer for autocomplete and code suggestions.

By utilising AI tools like chatGPT and Copilot to write tests for your codebase, you would not only save time but also reduce the mental effort needed, making the testing process more efficient.


Maintaining the Momentum

To guarantee a successful test-driven project, you need momentum! However, Introducing a new process is always challenging, and resistance is natural, so don't expect the journey to be all sunshine and rainbows.

So, how do you maintain momentum despite potential pushback?

Don’t aim for perfection. Instead, focus on incremental improvements. Remember that you’re working with humans, so mistakes will happen. Rather than focus on their mistakes, highlight the small wins and praise your team members for their efforts.

That way, they would be more likely to improve their testing practices over time. As the team begins to see the benefits of testing in their daily work, adoption will naturally increase.


Measuring Impact and Success

In the words of W. Edwards Deming, "Without data, you're just another person with an opinion."

You must have a way to track your success, as without it, there's no objective way to assess if the introduction of tests is benefiting the project.

How do you do that?

Prioritize test coverage over code coverage. Test and code coverage are different measures of test comprehensiveness of your codebase. However, Unlike code coverage, which measures how much of your codebase is tested, test coverage delves deeper into the quality aspect, assessing if the tests effectively catch bugs and improve code quality.

By prioritizing the relevance of your tests over test coverage, you can introduce tests into your codebase without feeling overwhelmed, even in a large project. It also provides more confidence in the reliability of your project quicker.



Is that all? Well, yes. By implementing these steps, beginning with features in development and choosing appropriate tools and frameworks, you can gradually introduce stability into any project of any size.

What you need to avoid is trying to fix every problem all at once. It’s a gradual process. The testing debt didn’t all get there in a day, so don’t expect to fix it in a day either.

Instead, start small, incorporate simple tests into your daily workflow and encourage your team to do the same. Embrace the errors (you’ll make many of them), and learn from them. Each one brings you closer to a more stable codebase.

Start working towards a more stable project today, one test at a time.

Jahdunsin Osho

Written by Jahdunsin Osho

Founder and Tech Lead at Edubaloo, is passionate about providing affordable quality education for students across Africa. Prior to this, he worked at several startups, building scalable backend systems, developing consumer blockchain applications and core blockchain infrastructures. Impact-driven, Jahdunsin leverages his non-technical skills in SEO, copywriting, and paid advertising to ensure that the products he builds reach the target audience.