How our QA process catches bugs before you see them
Good QA is not a final click-through before release; it is a set of layers that catch different failures at different points, plus deliberate edge-case hunting for the things users actually hit: empty states, interruptions, lost networks, denied permissions, and the one device nobody tested. Most bugs that reach users were findable before release. They were missed because testing stopped at "it works" instead of asking "what breaks it." This is our actual process, not a list of platitudes.
Why most bugs users meet were findable
Most bugs that reach a user were not exotic or unpredictable; they were findable, and they slipped through because testing confirmed the happy path and stopped there. The person who builds a feature naturally tests that it does what they intended, which is exactly the blind spot: they do not test what they did not intend, and that is where the defects live.
This is the honest opening because it reframes what QA is for. The job is not to verify that the software does what it is supposed to do when used correctly; developers already check that. The job is to find what it does when used incorrectly, interrupted, starved of network, denied a permission, or run on a device the team never held. Those situations are not rare edge cases from the user's side; they are Tuesday. A phone call arrives mid-task, a form is submitted empty, a connection drops in a lift. Calling these "edge cases" is a developer's framing; to the user they are just how life uses the app. Good QA exists to meet the software in those conditions before the user does, which means thinking adversarially about a thing you want to work.
The layers: what gets tested where
QA is not one activity but several layers, each catching a different class of problem at a different time, and understanding which layer catches what is how you avoid both gaps and wasted effort. A defect caught at the unit layer is cheap; the same defect caught by a user is expensive and public. The table below is the shape of it.
| Layer | What it catches | When it runs |
|---|---|---|
| Unit and developer checks | Logic errors in isolated pieces | During development, before merge |
| Functional testing | Features not doing what they should | As features complete |
| Cross-device and cross-browser | Environment-specific breakage | Before release, on real devices |
| Regression | Old bugs returning, new changes breaking old features | Every release, ideally automated |
| Exploratory (the detective pass) | The unscripted, unexpected, and interrupted | Continuously, especially near release |
| User acceptance (UAT) | Does it actually meet the real need | Before sign-off |
The layer that separates a mature process from a checkbox one is the exploratory pass, the detective work. Scripted tests find what you thought to write down; exploratory testing finds what you did not, because a tester is actively trying to break the thing rather than confirm it. No single layer is sufficient. Skip regression and old bugs return; skip exploratory and the surprising failures ship; skip real-device testing and the environment gets you. The layers are not a menu to pick from, they are a stack that each catch what the others cannot.
Hunting edge cases: how we think about breaking things
Edge-case hunting is not random; it is systematic pressure on a small set of categories where software reliably fails, applied deliberately rather than hoped for. The mindset is to stop asking "does this work" and start asking "what would make this fall over," then go do those things on purpose.
The categories are consistent enough to name. Empty states: what does the screen do with no data, no results, a first-run user with nothing yet? Interruptions: a call, a notification, the app backgrounded and restored, the screen locked mid-action. Network loss: the connection drops during a save, comes back, is slow rather than absent, or flaps on and off. Permissions: the user denies location or storage or camera, or grants it then revokes it later. Device fragmentation: small screens, large screens, old OS versions, and manufacturer quirks, which on Android is a genuine testing surface rather than a footnote. Each category is a place to push, not a box to tick, and the value is in actually performing the awkward sequence, denying the permission, killing the network at the wrong moment, rather than assuming it is handled. This is the "detective" part of the work: you are looking for the ways a confident piece of software quietly assumes the world will behave.
Mobile vs web testing: what actually differs
Mobile and web testing share the fundamentals but diverge sharply on environment and interruption, and treating them as the same is how mobile-specific bugs escape. The core discipline, functional checks, regression, exploratory pressure, is common; what changes is the terrain that terrain-specific failures come from.
Web testing concentrates on browser and viewport variety, and on the fact that users can do unexpected things with the back button, refreshes, and multiple tabs. Mobile testing adds a harder environment: real device fragmentation, OS-version differences, permissions models, battery and performance constraints, and above all interruptions that the operating system itself imposes, calls, notifications, and the app being killed in the background to reclaim memory. A media feature that plays perfectly in a browser tab has a whole extra life on a phone, as our Android team wrote about in building a production Android media player, where the interruptions were most of the work. The practical rule is that mobile testing must happen on real devices across a real spread, because the failures are environmental and an emulator hides exactly the differences that cause them.
What "done" means before release
"Done" is not "the tester finished clicking"; it is a set of exit criteria agreed before testing starts, so that release is a decision against a standard rather than a feeling. Without stated criteria, "done" quietly becomes "we ran out of time," which is how known-shaky software ships.
Honest exit criteria are specific to the project's risk, but the shape is consistent: the planned test coverage has actually been executed, not just intended; known defects are either fixed or explicitly accepted with a reason, not silently carried; regression has confirmed that new work did not break old work; and the real-device and edge-case passes have been done, not deferred. The important word is explicit. There is nothing wrong with releasing with a minor known issue if someone accountable decided to, in the open, with a plan to fix it. There is a lot wrong with releasing while pretending the issue is not there. "Done" is a shared, stated bar, and the value of QA is partly in forcing that bar to be named.
What we do not do
The honest counterpart to describing a process is naming its limits, so here is what we do not claim: we do not pretend everything is automated, we do not promise zero bugs, and we do not treat testing as a rubber stamp at the end. Those claims sound impressive and are usually a sign of a process that is thinner than it looks.
Full automation of everything is neither realistic nor desirable; automation is powerful for regression and repetitive checks and useless for the exploratory judgement that finds the surprising failures, so we automate where it pays and test manually where a person trying to break things is the only thing that works. Zero bugs is not a target a truthful team offers, because software of any complexity ships with unknowns; the target is that the bugs which escape are rare, minor, and quickly closed, and that each one teaches the process something. And testing is not a final gate bolted on after development, because a gate at the end can only reject, not improve; the value comes from testing throughout. If you are evaluating a software partner, the QA claims are worth pressing on, which is part of why we wrote about red flags in software proposals and how to evaluate a software development company. A team that tells you the truth about what its testing does and does not cover is telling you something important about the software you will get. See how this fits the rest of delivery on our services page, or talk to us about the standard your project needs.