QA Engineer
Produces trustworthy information about software quality by designing the cheapest tests that find the most damaging bugs, automating the stable and exploring the unknown.
Also known as: Quality Assurance Engineer, Test Engineer, SDET, Quality Engineer
It is a starting point, and parts of it may be thin, generic, or wrong. If you do this work, help us fix it — no GitHub account needed.
Purpose
A QA engineer exists because shipping software is a bet against the unknown, and someone has to make that bet honestly. The discipline is not about clicking buttons to find bugs; it is about producing trustworthy information about quality so the people who decide to ship are deciding with their eyes open. Code is written by optimists who tested the happy path; QA is the professional pessimist who asks "what did we not think of?" and answers with evidence. The cost of a defect rises by orders of magnitude the later it's found — and users will find, within hours, every state the team convinced itself wouldn't happen.
Core Mission
Give the team the truth about whether the software does what it should and fails safely when it can't — by designing the cheapest tests that find the most important bugs, automating what's stable, and exploring what isn't.
Primary Responsibilities
The visible work is finding bugs; the actual work is risk management and information. A QA engineer defines the test strategy for a feature or release; designs test cases from requirements, equivalence classes, and boundary analysis; runs exploratory sessions to find what scripted tests miss; builds and maintains automated suites across the test pyramid; triages and reports defects so they're reproducible and prioritized; advocates for testability and shifting left; owns the flaky-test problem; gates releases with a clear risk readout; and after incidents, asks why a class of bug escaped. The deepest part of the job is deciding what not to test, because exhaustive testing is impossible and attention is the scarcest resource.
Guiding Principles
- Quality is information, not a gate. Your product is a confident, evidence- backed answer to "what's the risk if we ship now?" The decision belongs to the team; the truth belongs to you.
- Testing shows the presence of bugs, never their absence. (Dijkstra.) You can never prove software correct by testing, so spend effort where a bug would hurt most.
- Risk-based, not coverage-based. Test where probability of failure times cost of failure is highest. A 1% feature with catastrophic failure outranks a high-traffic feature that degrades gracefully.
- Shift left, shift everywhere. The cheapest bug is caught in the requirement or the unit test. Get into design reviews; don't wait for a build.
- Automate the regression, explore the new. Machines are tireless at checking known behavior; humans are irreplaceable at discovering unknown behavior.
- A flaky test is worse than no test. A suite people don't trust gets ignored, and then real failures hide in the noise. Quarantine and fix flakiness ruthlessly.
Mental Models
- The test pyramid (and the ice-cream-cone anti-pattern). Many fast, isolated unit tests at the base; fewer integration tests; a thin layer of slow E2E tests at the top. An inverted pyramid (mostly slow UI tests) is expensive, flaky, and slow to diagnose.
- The defect cost-escalation curve. A bug's cost to fix roughly multiplies by 10 at each stage it survives — requirement, design, code, test, production. This is the entire economic case for shifting left.
- Oracles. How you know something is wrong: the spec, comparable products, user expectations, prior behavior, the docs. Naming the oracle keeps testing from being "feels off."
- Exploratory testing as simultaneous learning, design, and execution. (Bach/Bolton.) You design the next test from what the last one taught you, steered by a charter rather than a fixed script.
First Principles
- You cannot test everything; the input space is effectively infinite, so every testing strategy is a sampling strategy — make the sampling deliberate.
- The absence of a failing test is not evidence of correctness; it may be evidence the test was too weak.
- A bug found is cheap; a bug shipped is expensive; a bug nobody can reproduce is the most expensive of all.
Questions Experts Constantly Ask
- What's the worst thing that could happen if this feature is wrong, and who gets hurt?
- What did the developer assume that the user won't?
- What are the boundaries, the empty cases, the nulls, the max values?
- What happens under concurrency, slow networks, time-zone changes, and interruption?
- Is this test checking behavior, or just re-asserting the implementation?
- Why did this bug escape — what test or process would have caught it?
Decision Frameworks
- Automate vs. test manually. Automate stable, repetitive, high-value regression checks; test manually (and exploratorily) anything new, subjective, visual, or changing weekly. Automation pays back only if the feature outlives the maintenance cost.
- Risk-based prioritization. Plot features on likelihood × impact; give the top quadrant deep testing, the bottom a smoke test, and document what you consciously chose not to cover.
- Pyramid placement. For each check, push it to the cheapest level that can catch the bug — a unit test over an integration test over an E2E test.
- Block vs. ship-with-known-issues. A bug blocks release if it threatens data integrity, security, money, or safety, or has no workaround; otherwise it ships logged with severity and a follow-up, because perfect is the enemy of shipped.
Workflow
- Understand the change and its risk. Read the requirement, design, and diff. Ask what could break and who it affects.
- Define strategy. Decide what to test, at what level, manually vs. automated, and explicitly what's out of scope.
- Design cases. Derive from requirements, equivalence classes, boundaries, error paths, and the oracles you'll use to judge pass/fail.
- Explore. Time-boxed charter-driven sessions to find what scripts miss — odd sequences, interruptions, bad data.
- Automate the keepers. Promote stable, valuable checks into the suite at the right pyramid level; keep them fast and deterministic.
- Triage defects. Reproduce, isolate, and write a clear report (steps, expected, actual, environment, evidence) with severity and priority.
- Report readiness and learn from escapes. Summarize coverage, open risks, and a ship/no-ship recommendation in business terms; when a bug reaches production, run a blameless analysis and add the missing test — fix the class, not the instance.
Common Tradeoffs
- Test coverage vs. release velocity. More tests catch more bugs and slow every release; the right depth depends on the cost of the bug, not a coverage percentage.
- Automation investment vs. maintenance cost. Automated suites pay back over time but rot with the UI; brittle E2E tests can cost more than the bugs they catch.
- Strict gates vs. team trust. Block too much and you become the bottleneck everyone routes around; block too little and quality erodes — calibrate to real risk.
Rules of Thumb
- If a test is flaky, it's a bug — in the test or the system — not noise to retry past.
- The bug you can't reproduce, you can't fix; spend the time to nail the repro.
- Test the boundaries first; that's where the bugs live.
- Severity is "how bad," priority is "how soon"; never conflate them.
- A good bug report lets a developer reproduce it without talking to you.
- Measure escaped defects, not bugs found; the ones that got past you matter more.
Failure Modes
- The flaky-suite death spiral. Intermittent failures get "retried" until the team ignores red, and a real regression sails through unseen.
- Counting instead of judging. Reporting "847 test cases passed" instead of "the payment path is high-risk and under-tested."
- Testing the implementation, not the behavior. Tests so coupled to internals that any refactor breaks them, punishing exactly the cleanup you want.
Anti-patterns
- Happy-path-only testing — verifying the demo works, ignoring the error and edge cases where users live.
- Bug reports as accusations — "it doesn't work" with no steps, environment, or evidence.
- Sleep-based synchronization —
sleep(5)in tests, the number-one source of flakiness and slowness. - Shared mutable test data — tests that pass alone and fail together because they trample each other's state.
- Coverage as a goal — chasing 100% line coverage with assertion-free tests that prove nothing.
Vocabulary
- Test pyramid — the ratio of many unit, fewer integration, few E2E tests.
- Flaky test — a test that passes and fails on the same code, non- deterministically.
- Exploratory testing — simultaneous learning, test design, and execution, steered by a charter.
- Severity vs. priority — how damaging a bug is vs. how urgently to fix it.
- Equivalence partition / boundary value — input classes and their edges, the prime hunting ground for bugs.
- Shift-left — moving testing earlier into design and development.
- Regression — a previously working behavior that a change broke.
- Test double (mock/stub/fake/spy) — stand-ins that isolate the unit under test.
Tools
- Selenium / Playwright / Cypress — browser automation; Playwright and Cypress favored now for speed and auto-waiting over sleeps.
- Appium / Espresso / XCUITest — mobile UI automation.
- JUnit / pytest / Jest / TestNG — unit and integration test runners.
- Postman / REST-assured / k6 — API functional and load testing.
- Jenkins / GitHub Actions / GitLab CI — to run suites on every change.
- JIRA / TestRail / Zephyr — defect tracking and test-case management.
- BrowserStack / Sauce Labs — device and browser farms for the matrix.
Collaboration
QA sits at the seam between what was promised and what was built, working with developers (who must see QA as a partner, not an adversary), product managers (who own acceptance criteria and risk appetite), designers, and operations. The healthiest pattern is QA in the room at requirement and design time, asking "how will we test this?" before a line is written — that question alone improves the design. Bug reports are a communication craft: precise, reproducible, blame-free, with evidence. The recurring friction is the developer-QA dynamic; the cure is shared ownership and a culture where finding a bug is a team win. The best QA engineers make developers better testers and put themselves slowly out of the bug-finding business.
Ethics
QA is often the last person who can say "this isn't safe to ship" before users are exposed — a quiet ethical responsibility. Core duties: report risk honestly even when it's unwelcome and the deadline is tomorrow; never sign off on something you haven't actually verified; protect users by testing accessibility, privacy, and security paths, not just features that demo well; refuse to bury a known severe defect for schedule's sake without an accountable owner deciding openly; and never copy production PII into insecure test environments. The hardest moments are when business pressure wants a "looks tested" sign-off — integrity means stating the risk clearly and letting the accountable owner decide on the record.
Scenarios
A login bug that "can't be reproduced." Developers keep closing a report of intermittent login failures as irreproducible. The expert treats intermittent as a clue and finds the failures correlate with users in time zones where the local date is already "tomorrow" relative to the server. The token expiry check compares a client timestamp to a server one without normalizing to UTC, so it intermittently rejects valid tokens around midnight. Now reproducible by setting the device clock, it's fixed in minutes — and the expert adds boundary tests for midnight, year-end, and DST, the whole untested class.
A test suite nobody trusts. A team's CI is red half the time, and engineers
just hit "re-run." The expert treats this as the top quality problem, because a
suite you ignore is worse than none. They quarantine the worst offenders (with
tickets and owners) and trace the root cause to sleep()-based waits and tests
sharing an un-isolated database. They replace sleeps with explicit
wait-for-condition, give each test its own transactional fixture, and restore the
rule that red means stop. The next real regression gets caught.
Risk-based triage under a hard deadline. A release is due Friday with 40 open bugs and no time to fix all. The expert sorts by risk: a data-corruption bug in billing and a security issue in password reset are blockers (catastrophic, no workaround); a misaligned icon and a typo ship logged; a slow report export gets a documented workaround and a fast-follow ticket. They write a one-page readiness summary — "two blockers must fix, six ship with workarounds, the rest cosmetic" — and hand the ship decision to the product owner with the risks named, so the team ships informed, not blind.
Related Occupations
A QA engineer shares the software engineer's craft but inverts the optimism: where developers build, QA professionally doubts. They overlap heavily with SDETs and automation engineers who write the test code, and with site reliability engineers who test resilience in production. Security engineers apply the same adversarial "how does this break?" mindset to attackers. Product managers own the acceptance criteria QA verifies against. Mobile and embedded developers depend on QA's discipline for device and lifecycle matrices that are murder to cover by hand.
References
- Lessons Learned in Software Testing — Kaner, Bach, Pettichord
- Agile Testing — Lisa Crispin & Janet Gregory
- Explore It! — Elisabeth Hendrickson
- ISTQB Foundation Syllabus — istqb.org
- The Practical Test Pyramid — Ham Vocke (martinfowler.com)