LLM.coPrivate, self-hosted LLM deployments
Legal AI infrastructure for firms
AI RFP discovery and response drafting
Automatic.coBusiness process automation
Secure AI virtual data rooms70/20/10
Pyramid ratio we build to
Unit, integration, E2E
0
Flaky tests tolerated
Fixed in a sprint or deleted
100%
Suite yours at handover
Runs in your CI, not ours
390+
Projects shipped
Since 2013
What you are buying
Five kinds of testing sold as one line item
These have different costs, different maintenance burdens and different failure modes. Quoting them as a single number is how a testing budget disappears without anyone being able to say what it bought. None of them substitutes for another, and treating one as a cheaper stand-in for the rest is the fastest way to end up with none of them done well.
Unit tests
Fast, isolated checks on a single function or class, run in seconds and on every commit. They catch logic errors early and cheaply, but a green unit suite proves nothing about whether the pieces work together — that is a different test's job entirely.
Integration tests
Verify that your code talks correctly to the database, the queue, or the third-party API it depends on. This is where most real production bugs actually live, because two individually correct components can still disagree at the boundary about what a null value or a webhook payload means.
End-to-end tests
Drive a real browser or app through a complete user journey — sign-up, checkout, the workflow that makes money. They are the slowest and most expensive tests to write and maintain, so they belong on the handful of paths where a failure is unacceptable, not on everything the interface happens to do.
Load and performance testing
Establish what breaks first as traffic climbs, and at what number, rather than a general feeling that things are fast enough. Replaying real traffic patterns against staging with a tool like k6 or Gatling tells you the actual ceiling before a launch or a marketing push finds it for you.
Manual exploratory testing
A skilled tester using the product without a script, trying the things a written test case would not think to try. It is the one form of QA that gets better with human judgment rather than worse, and it reliably finds the class of bug automation is structurally blind to.
Regression testing
Re-running existing tests after a change to prove you did not break what already worked — the job a growing automated suite does best, because it never gets bored of checking the same two hundred things before every release. It pays for itself once doing the same check by hand starts taking longer than the change itself did.
Test strategy
The test pyramid, and why most teams invert it
The pyramid is a diagnostic more than a law. It describes where your bugs actually come from, and most codebases we are asked to fix have it backwards. Getting the shape right is worth more than adding tests at any single layer, because the wrong shape means you are paying maintenance cost on the tests least likely to catch the next real bug.
The shape that actually works
Many fast unit tests at the base, fewer integration tests in the middle, a small number of end-to-end tests at the top covering only the journeys where failure is unacceptable — roughly 70/20/10. It is a ratio, not a rulebook, and the right shape for your system follows where its bugs have historically come from.
Most teams build an ice-cream cone instead
Dozens of slow, brittle browser tests exercising the whole interface for every scenario, and almost nothing underneath. Each one takes minutes to run and breaks when a button moves three pixels, and the suite becomes something engineers route around rather than something they trust.
When not to automate
A UI that is being redesigned every sprint is not worth locking down with end-to-end tests you will delete next month — test the logic underneath instead and let a person click through the screens until the design settles. A one-off data migration gets a manual verification checklist, not a test suite that runs exactly once and is then dead code forever.
The suite for a codebase that never had one
You do not retroactively write tests for everything — that is a multi-month project nobody will fund and nobody will thank you for. Start with the paths that would lose money or data if they broke, add a test the next time a bug is fixed nearby, and let coverage grow along the seams the code actually moves through.
A strategy is a set of decisions, not a diagram
The useful output of a strategy exercise is a short, specific list: which ten paths get thorough automated coverage this quarter, which get a smoke test, and which stay manual on purpose. A pyramid diagram with nobody's name attached to any layer is a poster, not a plan.
What it costs
QA and testing services pricing
Real ranges. The variable that moves a quote is not test count — it is how much of the codebase was written with testability in mind, and how much untangling has to happen before a fake database or a mock queue can even be wired in. A codebase with no dependency injection and a lot of static state costs more to make testable than it costs to actually write the tests once it is.
| Engagement | Commitment | Timeline | What's included |
|---|---|---|---|
| Test strategy audit | Fixed scope | 2 – 3 weeks | Read your codebase, identify the highest-risk untested paths, hand over a written plan and a costed backlog. Yours to run with or without us. |
| Core suite build | Fixed scope | 4 – 8 weeks | Unit and integration coverage on the paths that would lose money or data, wired into CI so a red build blocks a merge rather than getting merged around. |
| End-to-end suite + CI pipeline | Fixed scope | 3 – 6 weeks | A small, deliberately limited suite on Playwright or Cypress covering the handful of journeys that must not break, plus the pipeline wiring to run it on every pull request. |
| Load and performance testing | Fixed scope | 2 – 5 weeks | Scripted load tests against staging with a named tool, a report on where the system actually breaks, and fixes prioritized by cost to fix against cost of the outage. |
| Embedded QA engineer | Ongoing retainer | Ongoing | A senior QA engineer inside your sprint writing tests as features ship, rather than auditing after the fact — the arrangement that actually keeps a suite from rotting. |
Ranges assume US-based senior engineers and include CI wiring and a handover runbook rather than quoting them separately. A quote well below these bands usually buys a suite that passes today and rots within two sprints, because nobody budgeted for maintaining it.
Coverage and flakiness
The metrics that mislead, and the one that doesn't
A number on a dashboard is easy to report and easy to get wrong. Here is what we actually watch instead. None of the metrics below replace judgment about which fifty lines in the codebase would actually hurt if they broke.
100% coverage is not the goal
A line can execute during a test without anything being asserted about its correctness, so a 100% badge proves the suite ran, not that it verified anything. Chase the paths that matter to the business, not the number on the dashboard.
A flaky test is worse than no test
A test that fails for reasons unrelated to the code teaches engineers to re-run the build instead of reading it. Within a few weeks, a genuinely broken build gets the same shrug and the same re-run, and the whole suite has quietly stopped doing its job.
Fix it or delete it, on a deadline
A flaky test gets one sprint to be fixed and is then deleted — not muted, not skipped indefinitely behind a comment nobody will revisit. A disabled test left in the file forever is a lie the suite tells about its own coverage.
Mutation testing tells you what coverage cannot
Tools like Stryker or PIT deliberately break your code and check whether a test notices. A suite that misses most of the mutations is asserting nothing meaningful even at 90% line coverage, and that gap stays invisible until someone goes looking for it.
A suite needs an owner, not just a runner
Tests need an owner the same way code does: someone who gets paged when a false negative slips through, and who has the authority to delete a test that no longer earns its runtime. An orphaned suite nobody owns is where flaky tests go to multiply, one skipped assertion at a time.
Build vs. buy
Should QA be outsourced at all?
Sometimes. The honest answer depends on whether the work is a permanent capability or a bounded, specific job. Get that distinction wrong and you either pay indefinitely for a function that should have been a skill your own team learned, or you try to build out a permanent team for a problem that needed three weeks of outside help.
Testing that lives outside the team decays
A separate QA function bolted onto engineering after the fact tends to test what was built last sprint, permanently a step behind, and treats a red build as someone else's problem to triage. The healthiest version of QA is a skill the development team owns, not a department downstream of it.
Where outsourcing genuinely helps
Standing up the first real suite on a codebase that has never had one, load-testing before a launch nobody on staff has run before, or an independent audit when a team is too close to its own blind spots. These are bounded engagements with a clear handover, not a substitute for permanent headcount.
The CI wiring is not optional
A test suite that only runs on someone's laptop is a suggestion, not a gate. Tests need to run on every pull request — GitHub Actions, CircleCI, whatever you already use — and a failing run has to actually block the merge, or the suite is decoration.
The honest recommendation, most of the time
Build testing into the development team, and use outside help for the specific, bounded jobs — strategy, an initial suite, load testing — that are inefficient to staff permanently. A QA function with no authority to block a bad build is not quality assurance; it is a report nobody has to act on.
A handover has to be real, not nominal
If outside help builds the suite, the engagement isn't finished until someone on your team can add a test, debug a failure, and explain what the CI pipeline does without calling anyone. A suite that requires the vendor to touch it every time it breaks was never actually handed over.
How an engagement runs
From audit to a suite your team owns
Week one is an audit: read the codebase, find the paths that would lose money or data if they broke, and rank them by risk rather than by ease of testing. The weeks after that add unit and integration coverage along those paths, wire the suite into CI so a failing test blocks a merge, and layer in the handful of end-to-end journeys that justify their maintenance cost. Handover includes the suite itself, the CI configuration, and a written note on what was deliberately left untested and why. Nothing in that sequence assumes the codebase already has tests; where it doesn't, week one's audit is what turns an intimidating blank slate into an ordered, costed backlog.
Related
Related services
Testing is rarely bought on its own for long. These are the services it most often sits beside.
Questions
Frequently asked questions
What teams ask before a first call.
A strategy audit is the smallest engagement here. A core unit and integration suite is the largest, with a scoped end-to-end suite and CI pipeline in between. Load testing is quoted separately because it needs a different tool and a different skill.
What moves the number is how much of the codebase has no seams to test against. Code written without testing in mind often needs refactoring before a test can be written at all, and that is the work people do not budget for.
It is a shape, not a law: many fast unit tests, fewer integration tests, a small number of end-to-end tests covering only the journeys where failure is unacceptable — roughly 70/20/10. Most codebases we are asked to fix have inverted it, with a slow pile of brittle browser tests and almost nothing underneath, and the fix is not deleting the end-to-end tests — it is building the base beneath them.
The pyramid is a diagnostic more than a target. If your CI run takes forty minutes and mostly exercises the browser, the shape is backwards regardless of what a coverage dashboard says. A CI run under ten minutes with confidence to match is the actual goal, not a specific ratio enforced for its own sake.
No, and a vendor who promises it is selling you a number instead of a result. Coverage measures whether a line executed during a test, not whether anything meaningful was asserted about it, so a codebase can hit 95% and still ship a broken checkout.
Set coverage by risk instead: the paths that lose money or data if they break get thorough coverage, the settings page nobody has touched in a year gets none, and that allocation is a decision worth writing down rather than a number to chase uniformly. We would rather show up with 60% coverage on the paths that matter than 95% that includes a settings page nobody asked us to test.
A test that fails intermittently for reasons unrelated to the code trains engineers to re-run the build rather than read the failure. Within a few sprints, a genuinely broken build gets the same shrug and the same re-run, and the team has quietly opted out of the one signal that was supposed to catch this.
Our rule is blunt on purpose: a flaky test gets one sprint to be fixed, and if it isn't, it's deleted rather than skipped indefinitely. A smaller suite people trust beats a larger one they've learned to ignore.
Build it in for the long run — testing owned by the engineers who write the code decays less, because a broken build is their problem the same afternoon it happens, not a ticket that lands on someone else's desk next week. Outsourcing works well for bounded jobs: standing up the first real suite on a codebase that never had one, an independent audit, or load testing before a launch nobody in-house has run before.
What doesn't work is a permanent, external QA function with no authority to block a merge. That arrangement produces a test report, not quality assurance, and the two get sold as one far more often than they should. If a QA vendor's contract doesn't give them the standing to fail a build, it's worth asking exactly what you're buying.
Both, and treating them as competitors rather than a division of labor is a mistake we see often. Automation is unmatched at re-checking the same thing thousands of times without getting bored; a skilled exploratory tester is unmatched at trying the thing nobody thought to script, which is where a surprising share of real bugs live.
We use manual testing deliberately rather than as a stopgap for missing automation — ahead of a release, on a UI still changing shape too fast to be worth locking into end-to-end tests, and anywhere judgment matters more than repetition.