Testing
Junior Questions
How do you mock API calls?
Option 1: Mock the fetch/axios function
Option 2: Mock the module
Option 3: Use MSW (Mock Service Worker)
MSW is preferred for realistic network mocking.
Why is this important?
- Stops extremely expensive third-party sandbox charges.
- Removes incredible external CI network dependencies totally.
- Simulates totally explicit completely chaotic 500 error cascades gracefully.
How do you organize test files?
Option 1: Colocated (Recommended)
Option 2: Separate test directory
Naming conventions:
Component.test.js- Unit testsComponent.spec.js- Specs (BDD style)Component.e2e.js- E2E tests
Why is this important?
- Colocates logic perfectly intuitively.
- Allows running test suites targeted by directory.
- Ensures team-wide structural consistency cleanly.
How do you test user interactions?
Using userEvent (preferred) or fireEvent:
userEvent simulates real user behavior; fireEvent is lower-level.
Why is this important?
- Simulates clicks
- Fires
- Mocks inputs.
What are the different query types in Testing Library?
| Query | Returns | Throws if not found | Use case |
|---|---|---|---|
getBy | Element | Yes | Element should exist |
queryBy | Element or null | No | Element might not exist |
findBy | Promise | Yes | Async element |
Priority order:
getByRole(accessibility)getByLabelText(forms)getByText(non-interactive elements)getByTestId(last resort)
Why is this important?
- Queries directly identical
- Allows targeting
- Finds
What are the different types of tests?
| Type | Scope | Speed | Confidence |
|---|---|---|---|
| Unit | Single function/component | Fast | Low-Medium |
| Integration | Multiple units together | Medium | Medium |
| End-to-End (E2E) | Full user flows | Slow | High |
The Testing Pyramid: Many unit tests at the base, fewer integration tests in the middle, fewest E2E tests at the top.
Why is this important?
- Establishes a firm quality baseline across every architectural layer.
- Prevents microscopic utility bugs from collapsing massive integrations.
- Creates extremely highly reliable release pipelines natively.
What is Mocking?
Replacing real dependencies with fake implementations to isolate the code under test.
Why is this important?
- Isolates unit contexts.
- Avoids heavy DB queries during tests.
- Eliminates network latency cleanly.
What is React Testing Library's philosophy?
"The more your tests resemble the way your software is used, the more confidence they can give you."
Key principles:
- Query by accessibility roles, labels, text (not implementation details)
- Test behavior, not implementation
- If you can't find an element, neither can a user
Why is this important?
- Tests precisely how actual physical human users
- Fundamentally
- Avoids strictly testing totally internal purely structural React state
What is the AAA pattern?
A structure for organizing test code:
Also known as Given-When-Then in BDD.
Why is this important?
- Fundamentally establishes
- Enforces exceptionally rigid functional discipline explicitly structuring clean tests naturally.
- Vastly accelerates explicit visual scanning
What is the Testing Trophy?
Kent C. Dodds' alternative to the Testing Pyramid:
Key idea: Integration tests give the best cost/confidence ratio.
Why is this important?
- Focuses heavily on integration tests.
- Provides the highest ROI for testing efforts.
- Shifts focus away from brittle unit tests.
What is the difference between Unit and Integration tests?
- Unit Test: Tests a single function or component in isolation. Dependencies are mocked.
- Integration Test: Tests how multiple units work together. Uses real (or partially real) dependencies.
Why is this important?
- Unit tests rigidly verify isolated pure micro-functions perfectly.
- Integration tests guarantee heavily complex structural components communicate seamlessly.
- Separates deeply isolated testing limits cleanly.
What makes a good test?
FIRST principles:
- Fast: Tests should run quickly
- Isolated: No dependencies on other tests
- Repeatable: Same result every time
- Self-validating: Pass or fail, no manual checking
- Timely: Written close to the code being tested
Additional qualities:
- Tests one thing
- Clear failure messages
- Readable as documentation
Why is this important?
- Massively ensures
- Eliminates explicitly frustratingly incredibly chaotic "Flaky" behaviors
- Tests strictly.
- Wait trimming tokens.
Mid-Level Questions
How do you test asynchronous components?
Why is this important?
- Awaits API data
- Ensures DOM rendering
- Fixes
How do you test custom hooks?
Using @testing-library/react-hooks or renderHook:
Why is this important?
- Extracts and tests logic independently from templates.
- Simulates React/Vue lifecycles programmatically.
- Guarantees functional composables perform reliably.
How do you test error states?
Why is this important?
- Verifies critical failure paths gracefully.
- Ensures users see appropriate fallback UIs.
- Validates try/catch logic natively.
How do you test time-dependent code?
Using fake timers:
Why is this important?
- Mocks native timers natively dynamically.
- Allows fast-forwarding extremely long animations.
- Eliminates waiting for physical setTimeout loops.
What are flaky tests and how do you fix them?
Flaky tests pass or fail inconsistently without code changes.
Common causes:
- Race conditions (async timing)
- Shared state between tests
- External dependencies
- Animation/transition timing
Fixes:
Why is this important?
- Saves
- Removes
- Enhances
What is Behavior-Driven Development (BDD)?
An extension of TDD focused on describing behavior in plain language.
Tools: Cucumber, Cypress (with Gherkin plugins).
Difference from TDD: BDD focuses on user behavior; TDD focuses on implementation.
Why is this important?
- Bridges the massive communication gap universally between Product Managers and Software Engineers entirely.
What is Code Coverage and what are its limitations?
Code coverage measures how much of your code is executed during tests.
Types:
- Line coverage: % of lines executed
- Branch coverage: % of if/else branches taken
- Function coverage: % of functions called
Limitations:
- 100% coverage ≠ bug-free code
- Doesn't measure test quality
- Can encourage writing tests just to hit numbers
Why is this important?
- Heavily exposes
What is Snapshot Testing?
Capturing output and comparing it to a stored version.
Pros: Easy to set up, catches unexpected changes. Cons: Easy to blindly update snapshots, large diffs are hard to review.
Best practice: Keep snapshots small and focused.
Why is this important?
- Tracks unintended structural DOM mutations.
- Provides quick baseline guarantees for static content.
- Warns visually when complex string arrays change.
What is Test Isolation and why is it important?
Each test should be independent and not affect other tests.
Problems with shared state:
- Tests pass individually, fail together
- Order-dependent failures
- Hard to debug
Solutions:
Why is this important?
- Prevents state leaking between tests.
- Ensures tests run deterministically.
- Allows running tests safely in parallel.
What is Test-Driven Development (TDD)?
A development process where you write tests before writing the implementation.
Red-Green-Refactor cycle:
- Red: Write a failing test
- Green: Write minimal code to pass the test
- Refactor: Improve code while keeping tests green
Benefits: Better design, fewer bugs, documentation through tests.
Why is this important?
- Reverses structurally identical fatal bug loops entirely.
- Massively limits dead code production natively.
What is the difference between Mock, Stub, Spy, and Fake?
| Type | Purpose |
|---|---|
| Stub | Returns pre-programmed responses. No verification. |
| Mock | Pre-programmed responses + verifies interactions (was it called?). |
| Spy | Wraps real implementation, records calls, allows assertions. |
| Fake | Working implementation not suitable for production (e.g., in-memory DB). |
Why is this important?
- Mocks verify behavior patterns explicitly.
- Stubs return controlled data safely.
- Spies observe execution thoroughly.
What is the difference between shallow and full rendering?
- Shallow rendering: Renders only the component itself, not children. Fast but less realistic.
- Full rendering (mount): Renders the entire component tree. Slower but tests real behavior.
Modern approach: Testing Library encourages full rendering to test real user experience.
Why is this important?
- Shallow tests isolate the current component
- Prevents deeply cascading child updates natively.
- Full renders test the entire DOM heavily.
Senior Questions
What is Contract Testing?
Verifying that API providers and consumers agree on the interface.
Tools: Pact, Spring Cloud Contract.
The contract is verified against the real provider during CI.
Why is this important?
- Ensures microservices communicate successfully.
- Validates API payloads strictly without relying on external databases.
- Guarantees contract bindings naturally securely.
What is Dependency Injection and how does it help testing?
Passing dependencies into a function/class instead of creating them internally.
Why is this important?
- Allows
- Trim limits
- Decouples dependencies.
What is End-to-End (E2E) testing?
Testing the entire application from the user's perspective, including frontend, backend, and database.
Tools: Cypress, Playwright, Selenium
Why is this important?
- Validates entire flows
- Acts as final gate
- Detects
What is Mutation Testing?
Automatically modifying your code (mutations) to see if tests catch the changes.
Example mutations:
- Change
>to< - Replace
truewithfalse - Remove statements
Tools: Stryker, PIT (Java).
Result: If tests still pass after a mutation, your tests have gaps.
Why is this important?
- Calculates true test coverage genuinely.
- Forces developers to write meaningful assertions.
- Prevents writing tests that natively always pass.
What is Visual Regression Testing?
Comparing screenshots of UI components to detect unintended visual changes.
Tools: Percy, Chromatic, Playwright's screenshot comparison.
Workflow: Baseline images → Run tests → Compare → Review diffs.
Why is this important?
- Catches rendering differences across browsers naturally.
- Prevents CSS regressions from leaking visually.
- Automates UI comparisons scaling flawlessly.
What is the difference between Cypress and Playwright?
| Feature | Cypress | Playwright |
|---|---|---|
| Browsers | Chromium, Firefox, (WebKit limited) | Chromium, Firefox, WebKit |
| Language | JavaScript only | JS, Python, C#, Java |
| Architecture | Runs in browser | Controls browser via CDP |
| Multi-tab | Limited | Yes |
| Parallel tests | Paid feature | Free |
| Debugging | Excellent time-travel | Trace viewer |
Cypress: Better DX, great for beginners. Playwright: More powerful, better for complex scenarios.
Why is this important?
- Cypress acts
- Playwright runs
- Both
When should you NOT mock?
- Pure functions: No side effects, no need to mock
- Simple value objects: Just use real data
- When testing integration: You want real interactions
- When mocks become complex: Sign of design issues
Over-mocking leads to tests that pass but don't catch real bugs.
Why is this important?
- Never mock core business logic inherently.
- Do not mock pure JS functions unnecessarily.
- When testing full integrated behavior natively.