99 Testing interview questions with detailed answers, sorted from basic to advanced. Free to practice, with progress saved automatically.
Software testing verifies that a product meets its requirements and exposes defects before users meet them, spanning QA fundamentals through automated tests. Questions cover test types and levels, black-box and white-box techniques, TDD, unit versus integration testing, Jest, React Testing Library, async UI tests, defect management, and edge cases.
and 43 more topics.
Jest is a JavaScript testing framework created by Meta (part of the OpenJS Foundation since 2022) that bundles a test runner, assertions, mocking, and coverage in one package. In a plain Node project it works with almost no configuration; Next.js configures it through next/jest. TypeScript…
describe, it (or test, two names for the same function) and expect are the three functions Jest provides out of the box. describe groups related tests into a suite, it defines one test case, and expect takes the actual value and attaches a matcher that…
jest.fn() creates a standalone mock function, jest.mock() replaces an entire module, jest.spyOn() wraps an existing method and calls the real implementation by default. In the example, getUserName calls fetchUser from the ./api module and then logs to the console. jest.mock('./api') turns fetchUser into a mock…
Vitest is a test framework built on Vite with a Jest-compatible API — it reuses the Vite config and transforms so tests need no separate setup, and runs faster by sharing Vite's transform pipeline and running tests as ESM. - Easy migration — from Jest…
Cypress is an E2E testing framework for the web that runs inside the browser, alongside the app. Selenium drives the browser from the outside through the WebDriver protocol, and the test code runs in a separate process. This test intercepts the POST /api/orders request and…
Playwright (Microsoft) is an E2E testing framework that runs tests in a separate Node process and drives the browser over a debug protocol. One test suite runs on Chromium, Firefox, and WebKit (Safari's engine), written in plain async/await. This test intercepts the /api/orders request and…
TDD (Test-Driven Development) means writing the test first, then writing the code that makes it pass, in a Red-Green-Refactor loop. - Red: write one test for the behavior you want and run it to see it fail. Failing for the right reason is what proves…
BDD (Behavior-Driven Development) grew out of TDD, but describes tests in terms of behavior the user or the business can see, rather than how the code is written internally. - Given-When-Then: Given is the starting context ('Given a user with $100 in their account'), When…
- Unit test: checks one small unit (function, class) in isolation with mocked/stubbed dependencies. Runs in milliseconds; a failure points at the exact spot → easiest to write, so write the most of these. - Integration test: checks several components working together — real DB,…
Snapshot testing turns output (a rendered component, a JSON object, a string) into text and saves it in a .snap file. Later runs compare the new output with the saved one; a single character of difference fails the test. If someone later changes status to…
Code coverage measures the percentage of code executed by tests — generated by Istanbul (Jest) or V8 (Vitest V8 provider). Metrics: - Statement coverage — % of statements executed. - Branch coverage — % of branches covered: every if/else/ternary/&&/ creates 2 branches; both true and…
A unit test checks a single function or class on its own, with dependencies (database, external APIs) replaced by mocks. An integration test checks several components working together, with real or minimally mocked dependencies. The example below has both, using Jest and Supertest: The first…
The most popular tooling is React Testing Library (RTL) running on a test runner: Jest or Vitest (Vitest is a common pick for projects that use Vite). RTL's philosophy is to test what a user sees and can do, not implementation details such as internal…
AAA (Arrange-Act-Assert) splits the body of a unit test into three parts, in order: prepare the data, invoke exactly one action under test, then check the result. Each part is separated by a blank line, so a reader can see at a glance what the…
MSW intercepts network requests at the Service Worker level (in the browser) or via msw/node (in Node.js) and returns mocked responses without changing application code. Unlike mocking fetch directly (jest.spyOn(global, 'fetch')): MSW intercepts at the network layer, so the app still calls fetch or axios…
A flaky test passes sometimes and fails other times with no change to the code. The real damage is not the failure itself but the team losing faith in the suite and starting to wave off genuine failures. Six usual causes: 1. Timing/async — the…
Coverage thresholds fail CI when coverage slips below a floor, declared in jest.config.js: - collectCoverageFrom matters more than it looks: without it, a file with no tests at all is never counted (Jest only measures files the tests import), and the number flatters you. -…
@testing-library/react has three query families, differing in what happens when the element is not there: - getBy — throws immediately. Use it when the element must exist; it fails fast with the clearest message. - queryBy — returns null. Use it to assert an element…
After coding, run through groups of cases, each group aimed at a different kind of bug. Example with binary search: If you accidentally write while left < right, normal cases may still pass but the single-element case [5] returns -1. That is why you test…
A dry run means reading code like the machine: pick a small input, step through each line and write down variable values after every step. When a value diverges from what you expect, you have found the bug without running the code. Dry run with…
Most coding-interview bugs fall into a few recurring groups. Knowing the list in advance tells you where to look during a dry run. Example of the "reusing the same element" bug in two sum: Because seen[num] = i runs before the check, when num =…
A useful technique is equivalence partitioning: split inputs into groups the code treats differently, pick one representative per group, and add the boundaries between groups. The reason: every value in one group goes through the same code path, so one value is enough; off-by-one bugs…
Both check quality, but answer different questions: - Verification — "Are we building it right?" Checks whether a work product/document conforms to the spec, design, and standards. Usually static (reviews, inspections, static analysis), without running the software. - Validation — "Are we building the right…
These form a causal chain, not synonyms: - Error (mistake) — a human action that produces an incorrect result, e.g. a developer misunderstands a requirement or mistypes. - Defect / Fault / Bug (flaw) — the flaw in the code or document that the error…
They differ by how much you know about the internal structure when designing tests: - Black-box — based on the spec/behavior, no knowledge of how the code runs. Techniques: equivalence partitioning, boundary value analysis, decision tables. Answers "given this input, is the output correct?". -…
- Functional testing — checks what the system does: do the features work per the requirements (login, billing, search...)? Focuses on behavior and results. - Non-functional testing — checks how well the system does it: quality attributes such as performance, load, security, usability, reliability, compatibility.…
- Severity — how badly the defect impacts the system, technically. Assessed by the tester (crash, data loss → high; a minor UI misalignment → low). - Priority — how urgently it should be fixed, from a business view. Decided by the PO/PM based on…
The standard flow from discovery to closure: 1. New — the tester has just logged the defect. 2. Assigned — a lead/PM assigns it to a developer. 3. Open / In Progress — the developer picks it up and starts fixing. 4. Fixed — the…
Two black-box techniques to cut the number of test cases while keeping good coverage: - Equivalence Partitioning (EP) — split the input domain into equivalence classes where every value is handled the same way. Test just one representative per class (both valid and invalid classes).…
Both are quick checks before deeper testing, but differ in scope and depth: - Smoke testing — broad and shallow. A fast pass over core functions to confirm the build is stable enough to test further (app launches, login works, main flow does not crash).…
- Static testing — examines a work product without running the code. It covers reviews, walkthroughs, inspections (documents, requirements, design, code) and static analysis (linters). Advantage: catches defects early and cheaply, even at the requirements stage — before they reach the code. - Dynamic testing…
The four levels go from small to large, each with its own goal and owner: 1. Unit / Component — tests individual modules/functions in isolation, usually written by developers. Fast, isolated, catches logic bugs earliest. 2. Integration — tests the interaction between components (module to…
- Re-testing (confirmation testing) — rerun the exact failed test case on the fixed build to confirm the defect is truly gone. Narrow scope, aimed at the spot just fixed. - Regression testing — rerun test cases for already-working areas to ensure a change/fix did…
The STLC is a structured sequence of testing activities, typically six phases: 1. Requirement analysis — analyze requirements, decide what is testable, clarify criteria. 2. Test planning — plan scope, strategy, resources, schedule, entry/exit criteria. 3. Test case design — write test cases, scenarios, and…
They differ by level of detail: - Test scenario — a high-level "what to test": a feature or flow to verify, e.g. "Verify the login feature". Answers what. - Test case — the detailed "how to test": includes preconditions, test data, steps, and expected result.…
The key point: Jest must know when the async operation completes — otherwise the test finishes before the assertions run and passes incorrectly. - async/await or return a promise — the standard approach: test('fetch', async () = { const data = await fetchData(); expect(data).toBe('ok') }),…
Do not try to cover the whole codebase. Start where bugs cost the most and where code is easiest to test. A practical order: 1. Set up the harness first — install a runner (Vitest/Jest), make pnpm test work with one command, wire it into…
Prioritise business logic first, UI second. Why: business logic (pricing, discount codes, permission checks, order state transitions) is where mistakes are unrecoverable, and it is usually pure functions — fast to write, milliseconds to run, almost never flaky. UI markup and class names churn constantly;…
Write the test first — and watch it go red before touching the code. The practical loop: 1. Reproduce the bug with the smallest possible test, using the exact failing data (order id X, input string Y). 2. Run it → it must fail. This…
There is no single accepted definition — which is why this is asked: to see whether you understand the purpose or just memorized labels. A workable distinction in practice, based on what the test controls: - Unit test: runs in-process only — no network, no…
Because the test mocked away the very part that has the bug. A mock replaces a real component with something you defined yourself, so it only proves the code calls what you imagined — not that the thing exists or behaves that way. Concrete failure…
Rule: never let tests depend on the real clock. Two approaches, the first preferred. 1. Inject time as a dependency. The function takes now (or a clock) instead of calling Date.now() itself. Tests pass a fixed instant, no extra tooling. 2. Fake timers when you…
Every non-deterministic source must be pushed to the boundary and replaced with a fixed value in tests. Randomness and UUIDs: do not call them inside business logic; accept them as parameters or mock the id module. Network: intercept at the HTTP layer instead of stubbing…
Factories beat hard-coded fixtures in most cases. A shared JSON fixture used by a hundred tests slowly accumulates "one more field" from everyone, and nobody dares change it for fear of breaking other tests. A factory builds a valid record with defaults and lets each…
Measure first, optimize second. Jest prints per-test timings with --verbose (add --slowTestThreshold=0 to see the time of every test file); Vitest uses --reporter=verbose. If Jest finishes but does not exit, add --detectOpenHandles to find handles that are still open. Usually a small share of the…
Testing Library ranks queries by how closely they mirror how a real user finds an element: 1. Accessible queries — getByRole, getByLabelText, getByPlaceholderText, getByText, getByDisplayValue. 2. Semantic queries — getByAltText, getByTitle. 3. Test ID — getByTestId, only when nothing else works. getByRole matches on the…
Four causes cover most cases: The text is split across several elements (1). getByText matches against individual text nodes by default, not the concatenated text of the whole subtree. To match the whole phrase, use a matcher function or query the parent and assert toHaveTextContent.…
fireEvent.click(el) dispatches exactly one DOM event at the element. userEvent.click(el) simulates the whole interaction sequence a browser produces for a real click: pointerdown, mousedown, focus, pointerup, mouseup, click. Where it matters in practice: - fireEvent.change(input, { target: { value: "abc" } }) assigns the value…
Drive the test the way a user drives the form: fill in bad values, submit, then assert the error messages appear and the submit callback was not called. Do not touch internal state or form-library internals. Points to keep in mind: - Use findBy for…
Intercept at the network layer (MSW or a mocked fetch), then assert what the user sees at each stage. Picking the right query in an async flow: - getBy for what is there immediately (skeleton, static heading). - findBy for what appears after the request…
MSW intercepts at the network layer (a Service Worker in the browser, an interceptor in Node), so application code has no idea it is being mocked — no need to patch fetch or your axios instance. Suite-wide setup: onUnhandledRequest: "error" is worth enabling: any request…
waitFor re-runs its callback on an interval (50ms by default) until it stops throwing, or the timeout (1000ms by default) expires. Three frequent mistakes: Cramming several assertions into one waitFor (1). If the first assertion fails, the rest never run, so when the test fails…
Use React Testing Library's renderHook — it renders a bare component just to call the hook and exposes its return value as result.current. Three common mistakes: - result.current is a snapshot. Do not destructure it into a variable (const { count } = result.current) and…
Create a custom render that wraps all providers and re-export it in place of RTL's render. Three details decide whether these tests are stable: - retry: false for React Query. By default the client retries three times with backoff, so error-path tests hang and then…
vi.mock (and jest.mock) is hoisted to the top of the file and runs before any import and before any variable declaration. That is what makes it possible to stop the real module from loading. Two fixes: In Jest the convention is to prefix the variable…
Do not wait on a real setTimeout — use fake timers and advance the clock yourself. Why it hangs: user-event v14 inserts its own delay between keystrokes with setTimeout. With fake timers installed and nobody advancing the clock, that timer never fires, so await user.type(...)…
Default to in-process HTTP: boot the app in memory and fire requests through the framework helper (supertest for Express/Nest, WebApplicationFactory for ASP.NET, MockMvc for Spring). No port is opened and no background server is needed, yet the request still goes through routing, middleware, validation, JSON…
A usable report answers four questions: what you did, what you expected, what actually happened, and where. - Title: one line with symptom plus context. "Order fails" is useless; "Checkout returns 500 when the discount code is expired" lets a developer narrow it down instantly.…
QA joins at refinement, not when a developer says "code is done". During refinement QA asks the questions that expose missing requirements: what shows on empty data, what an unauthorized user sees, whether a second submit creates a duplicate order. Fixing requirements here is far…
These bugs almost always come from environment drift, not from the code. Common sources, roughly by frequency: - Data: staging has a few hundred rows, production has millions. A query missing an index runs in 20ms on staging and 8 seconds in production. Real data…
Pick Testcontainers: on each test run the library starts a real Postgres/MySQL/Redis container through Docker, maps a random port, runs migrations, and tears the container down afterwards. Why not the other two: - In-memory SQLite is fast but a different dialect: none of Postgres's JSON…
Three options with different trade-offs: 1. Transaction rollback per test — open a transaction before the test, ROLLBACK after. Fastest, no manual cleanup. Limitation: the code under test must use that exact connection, so it breaks as soon as the app opens its own transaction,…
Do not copy it as-is. Production data contains personal information (emails, phone numbers, addresses, payment history); moving it to an environment with broader access is a disclosure risk and breaks the commitment made to users. A large dump also slows tests down and is not…
Three levels, used together at different layers rather than picking one: 1. Test doubles at the service layer (most cases). Put the third-party client behind your own interface and inject a fake. Here you verify what is yours: are the right arguments passed, does a…
Split it into two layers. Pure logic layer (most of the tests): the handler takes an already-parsed message and returns a result without connecting to the broker itself. Tests here are fast and cover what matters: - Valid message → correct record created, correct follow-up…
Before running anything you need numeric pass criteria, otherwise the result is just charts. The criteria have three parts: load level (concurrent users or requests per second), a latency threshold, and an error-rate threshold. Metrics to read in k6: - httpreqduration at p95/p99 percentiles, not…
Choose by risk, not by gut feeling or by the order of the test-case sheet. Priority order: 1. Revenue and blocking flows: login, payment, checkout, transactional notifications. Breakage here stops the business regardless of whether the release touched it. 2. Areas changed in this release:…
ISTQB Foundation (CTFL v4.0) lists 7 principles describing the limits of testing and how to test sensibly. The core idea: testing reduces risk, it cannot prove software is defect-free. 1. Testing shows the presence, not the absence of defects — testing finds bugs but cannot…
A test plan is the document that answers "test what, how, who tests, when, and when do we stop" for a project or release. It sits at the planning level; test scenarios and test cases sit at the execution level. Main contents of a test…
Chrome DevTools lets a tester pin down whether a bug is in the frontend or the backend before logging it, and attach evidence so devs fix it fast. Open it with F12 or right-click → Inspect. - Elements: inspect an element's HTML/CSS. Use it for…
Usability testing means having real users perform specific tasks on the product and watching where they struggle. Types are split along a few axes, each answering a different question. - Qualitative vs quantitative: - Qualitative: 5–8 people, observe and ask "why". Used to find problems…
Performance testing is the family of tests that measures how fast and stable a system is under a given load. Load testing is one type within it: run at the expected load (e.g. 500 concurrent users at peak) to see whether targets are met. The…
The SDLC (Software Development Life Cycle) is the sequence of phases for building software: requirements → analysis & design → coding → testing → deployment → maintenance. SDLC models differ in whether those phases run sequentially or iteratively, and when testing happens. Model How it…
Group them instead of listing at random: positive → negative per field → edge/security cases. Interviewers (Grab once asked for "negative cases only") score coverage and organisation, not count. Positive: - Correct username and password → lands on the home page, session created. - Username…
Automation pays off when a test must run many times on a stable part of the product: machines run fast and consistently, overnight or on every merge. It does not replace manual testing — it frees testers from repetition so they have time for exploratory…
API testing means sending requests straight to endpoints and checking responses without the UI, so it catches backend bugs earlier and is more stable than UI tests. For each API check at least: status code, response content, structure (schema), authentication/authorisation, and handling of bad data.…
A test report (ISTQB calls it a test completion report) summarises what was tested, what the results are and what risk remains, so decision makers (PM, PO, client) can decide whether to release. Readers rarely have time for details, so the conclusion goes first. Usual…
A framework is the shared skeleton that makes everyone write tests the same way: folder structure, element lookup, data loading, reporting, running in CI. The goal is fast addition of new tests and a single place to fix when the UI changes. Main components: -…
You cannot test until there are "no bugs" (ISTQB principle: testing cannot prove the absence of defects). A testing phase ends when the exit criteria agreed up front in the test plan are met — meaning the remaining risk is at a level stakeholders accept.…
Patterns in automation exist to solve one main problem: the UI and data keep changing, but you do not want to edit hundreds of tests each time. The most-asked pattern is the Page Object Model; the others support it. - Page Object Model (POM): each…
This is not about the pen — it checks systematic test thinking: ask for requirements first, then group tests (functional, non-functional, limits, safety) instead of naming a few random ideas. A framework for an elevator: 1. Ask for requirements first: apartment building or hospital? Maximum…