How to Run Backend Tests Smoothly and Effectively: Expert Tips from Tech Leads
Backend testing is a critical but often overlooked part of the software development lifecycle. While less visible than frontend testing, backend tests are essential for ensuring the reliability, performance and security of an application.
Consider these statistics:
- On average, bugs found in production cost 5X more to fix than bugs found during testing (Source)
- 56% of development teams say that most of their time is wasted due to a lack of testing processes (Source)
- Properly tested software can save companies up to $300B annually (Source)
Neglecting backend testing is incredibly costly. But approaching it haphazardly can also lead to slow, brittle tests that are a nightmare to maintain.
So how can you run backend tests that are both effective at catching bugs and efficient to write and maintain? To get answers, we turned to battle-tested tech leads at HubSpot who have built rock-solid backend testing suites for large-scale applications.
Here are their top tips and techniques for backend testing success.
Develop a Backend Testing Strategy
The first step to effective backend testing is to define your testing strategy. As a tech lead, you need to determine what to test, how to test it, and when to run those tests.
Some key questions to answer include:
- What are our top risks and priorities?
- What level of test coverage do we need?
- What types of tests will we focus on (unit, integration, etc.)?
- How often will we run the tests?
- What tools and frameworks will we use?
"The backend testing strategy is our team‘s game plan," says Jared Bhatti, Tech Lead at HubSpot. "It aligns everyone on goals and methodology so we‘re working efficiently toward a shared bar for quality."
Bhatti recommends targeting 80% code coverage for unit tests on critical paths and logic. For integration and end-to-end (E2E) tests, he suggests covering key workflows that map to top business objectives.
"We can‘t test everything, so we ruthlessly prioritize based on risk and impact," he says. "If a bug slips through in some edge case, that‘s less detrimental than a payment processing or security flaw."
Focus on Testing Boundaries
Many backend testing issues arise from tests that aren‘t properly scoped. Tech leads emphasize the importance of testing at boundaries rather than getting bogged down in implementation details.
"Each test should have a single, well-defined entry and exit point," says Bhatti. "We focus on testing the interface or ‘contract‘ of a module rather than every line of code within it."
Amy Farrell, Senior Engineering Manager at HubSpot, gives an example:
"Let‘s say we‘re testing a function that retrieves a user record from a database and returns it. The test shouldn‘t care about what SQL queries are used under the hood. It just needs to validate that when called with a user ID, the function returns the correct user data in the expected format."
This approach results in tests that are:
- Resilient to refactoring – The implementation can change without breaking the tests as long as the contract is upheld.
- Faster to run – Tests focused at boundaries tend to be much more concise.
- Clearer to understand – There‘s less irrelevant noise and complexity in narrowly-scoped tests.
Use Test Doubles Liberally
To test boundaries effectively, tech leads leverage test doubles (mocks, stubs, fakes, etc.) extensively. Test doubles stand in for real dependencies in tests, allowing you to easily isolate the unit under test.
"I start by mocking or stubbing any dependency that isn‘t the focus of my current test," says Rachel White, Senior Software Engineer at HubSpot. "This includes databases, third-party APIs, message queues, or even other modules owned by my team."
Test doubles provide several key benefits:
- Faster test runs – Mocked dependencies respond instantly rather than making time-consuming network calls.
- Deterministic results – You can precisely control the behavior and output of mocked dependencies.
- Fault tolerance – Tests aren‘t disrupted if a real dependency is down or unresponsive.
"The tradeoff is that mocked code can diverge from real implementations," notes White. "It‘s important to have some integration tests that validate real interactions."
Optimize Your Test Pyramid
The test pyramid is a model for balancing different granularities of tests, from unit to integration to E2E tests. A typical recommended balance is:
| Test Type | Proportion |
|---|---|
| Unit | 70% |
| Integration | 20% |
| E2E | 10% |
Unit tests form the base of the pyramid. They‘re the fastest to write and run, and the least brittle. As you move up the pyramid, tests provide more coverage but become slower and more prone to breakage.
"The exact balance depends on your context, but the pyramid shape tends to be optimal for backend testing," says Bhatti. "When teams get inverted pyramids or ice cream cones, it‘s a red flag."
An anti-pattern is relying too heavily on E2E tests that run through the UI. These are the most expensive and unreliable tests.
"You generally want a small smoke test suite of E2E tests to catch major user-facing bugs," says Farrell. "But most of your testing value comes from the lower levels of the pyramid."
Prioritize Fast Feedback Loops
Perhaps the most important factor in backend testing success is speed. Slow tests hinder development velocity and allow bugs to linger.
HubSpot tech leads offer several tips for keeping backend tests fast:
-
Set performance budgets – Establish a threshold for how long the full suite should take to run and track it over time. For example, HubSpot aims for 80% of builds to run in under 10 minutes.
-
Parallelize test runs – Split your test suite into multiple jobs that can be run simultaneously by your CI tool. HubSpot uses CircleCI to run over 20 parallel jobs.
-
Optimize setup/teardown – Practice good hygiene to efficiently reset state between tests. Use techniques like dependency injection for swapping between real and fake versions of components.
"We also use code coverage data to identify slower tests that may have too broad of scope," adds Bhatti. "Optimizing or splitting those helps keep the whole suite lean."
Make Tests a First-Class Citizen
Finally, tech leads stress the importance of treating tests as part of the product rather than an afterthought. This requires a shift in mindset and engineering culture.
"We make it clear that delivering a feature isn‘t done until it has proper tests in place," says Farrell. "Code reviews look just as closely at test code as production code."
Other tips for elevating tests in your development process:
- Make tests easily discoverable – Co-locate test files with the code they cover. Use clear naming conventions so developers can quickly find relevant tests.
- Run tests automatically – Configure your CI pipeline to automatically run tests on every pull request and block deploys if tests fail.
- Surface test results prominently – Display code coverage and test failure data on dashboards that the team monitors regularly.
- Celebrate testing wins – Recognize developers for increasing coverage or catching bugs in tests. Make it a point of pride to have well-tested code.
"When we make testing a requirement rather than a nice-to-have, quality soars," says Bhatti. "But it takes commitment from leaders to make it a priority."
Conclusion
Backend testing is hard. There‘s no way around that. But with the right strategy, processes and culture in place, you can overcome the challenges.
Key takeaways:
- Prioritize your testing efforts based on risk and business impact
- Design narrowly-scoped, boundary-focused tests
- Leverage test doubles to improve speed and reliability
- Balance your testing pyramid with an emphasis on unit and integration tests
- Optimize for fast feedback loops through parallelization and performance monitoring
- Treat tests as first-class citizens and a core part of your definition of done
Tech leads play a pivotal role in setting the tone and standards for backend testing. By implementing these tips and techniques from HubSpot‘s experts, you‘ll be well on your way to building a test suite that‘s an asset rather than a liability.
Remember, backend tests are your team‘s safety net. They provide the confidence to move quickly while catching bugs before they impact users. Don‘t neglect or haphazardly approach this critical investment.
Your backend systems are the foundation your application is built on. With a rock-solid testing strategy, you‘ll ensure that foundation remains stable and strong as you scale.
