Testing — Cheat Sheet

Tags: testing, tdd, bdd, unit-testing, integration-testing, e2e, jest, cypress

Level: intermediate

TL;DR: Core principles and practices of software testing, covering unit, integration, and E2E layers to ensure code reliability and catch bugs early.

Key concepts

Unit Testing focuses on isolating and testing individual functions, classes, or components.

Integration Testing verifies that different internal modules or external services work together correctly.

End-to-End (E2E) Testing simulates real user scenarios across the entire application stack from the UI to the database.

Test-Driven Development (TDD) requires writing failing tests before writing the implementation code using the Red-Green-Refactor cycle.

Behavior-Driven Development (BDD) structures tests around user behaviors and specifications using the Given-When-Then format.

Mocking replaces complex external dependencies with fake implementations to isolate the code under test.

Code Coverage measures the percentage of source code executed by your test suite across statements, branches, and functions.

The Test Pyramid emphasizes having a large base of fast unit tests, fewer integration tests, and very few slow E2E tests.

Typical questions and ready answers

Q: What is the difference between a mock and a stub?R: I use a stub to provide canned answers to calls made during the test. I use a mock when I need to verify that specific interactions, like calling a method with certain arguments, actually happened.

Q: Why do we need the Test Pyramid?R: I rely on the Test Pyramid because E2E tests are slow and brittle. By focusing heavily on unit tests, I get fast, deterministic feedback, which saves time and reduces flaky builds.

Q: How do you test a component that depends on an external API?R: I isolate the component by mocking the API client or intercepting network requests using tools like MSW (Mock Service Worker), ensuring the test is fast and does not depend on network availability.

Pitfalls and common mistakes

Testing implementation details and private methods instead of public behavior and user outcomes.

Writing flaky tests that pass or fail randomly due to race conditions, asynchronous operations, or shared state.

Chasing 100% test coverage at the expense of meaningful assertions, focusing on executing lines instead of verifying use cases.

Failing to clean up mocks, spies, or timers between test runs, which leads to test cross-contamination.

Snippets and commandsTypeScript

```import { calculateTotal } from './cart';

describe('calculateTotal', () => {

it('should apply a 10 percent discount when promo code is valid', () => {

const items = [{ price: 100 }, { price: 50 }];

const promoCode = 'DISCOUNT10';

const total = calculateTotal(items, promoCode);

expect(total).toBe(135);

});

});

```

To review

[ ] Dependency injection patterns to make code more testable.

[ ] Setting up and configuring MSW for frontend integration tests.

Jarvis Interviews
Jarvis