Brett Owers

Testing

Building robust systems from unit tests to network-level resilience.

The Testing Spectrum

Testing is not a single activity — it is a spectrum that spans from the smallest unit of code to the full behavior of a distributed system under real-world failure conditions.

At one end: unit tests — fast, isolated, cheap. They verify that individual functions behave correctly given known inputs. At the other end: chaos engineering — slow, expensive, but the only way to know if your system survives the conditions that will eventually arrive in production.

The art of QA is knowing where to invest across this spectrum for the system you are building. A toy project needs unit tests. A banking system needs everything.

The Layers

Unit

Individual functions and methods. Pure logic, no dependencies. Fast, deterministic, high coverage. Tools: Jest, pytest, XCTest, go test. Write these first and write the most of them.

Integration

Components working together. Database queries, API calls, service interactions. Slower but catches contract violations between layers. Tests that hit a real database catch bugs that mocked tests hide.

End-to-End

Full user flows through the system. Browser automation (Playwright, Cypress), mobile simulators (XCUITest, Detox). Expensive to write, expensive to maintain, but mirrors what real users actually do. Keep the count low and cover critical paths.

Contract

API boundaries between services. Schema validation, backward compatibility checks. Pact and similar tools let consumers and providers agree on the contract independently. Prevents "it works on my machine" across service boundaries.

Performance

Load testing (k6, Locust, Artillery), stress testing, soak testing. Finds bottlenecks, memory leaks, and scaling limits before users do. The question is not "does it work?" but "does it work under 10,000 concurrent requests?"

Chaos / Resilience

Intentionally injecting failure: network partitions, service outages, disk full, clock skew. Netflix's Chaos Monkey pioneered this. The premise: if you do not test failure, you do not know how your system fails. And it will fail.

The Test Pyramid vs. The Testing Trophy

The Test Pyramid (Mike Cohn, 2009): many unit tests at the base, fewer integration tests in the middle, fewest E2E tests at the top. The logic: unit tests are fast and cheap, E2E tests are slow and flaky. Optimize for speed and reliability by weighting toward the bottom.

The Testing Trophy (Kent C. Dodds, 2018): a rebalancing. Static analysis at the base, then unit tests, then a thick middle of integration tests, then a small top of E2E tests. The argument: integration tests give the most confidence per test because they test how components actually work together, not how they work in isolation. A mocked test that passes tells you the mock works. An integration test that passes tells you the system works.

Both models are useful. The pyramid optimizes for speed. The trophy optimizes for confidence. Choose based on what your system needs more: fast feedback (pyramid) or realistic coverage (trophy).

Testing Strategies That Matter

Test at the boundaries. The most valuable tests exercise the interfaces between components — API endpoints, database queries, external service calls. Bugs live at boundaries because boundaries are where assumptions from two different developers collide.

Make tests deterministic. A flaky test (passes sometimes, fails sometimes) is worse than no test because it erodes trust in the entire test suite. If a test depends on time, random values, or external services, mock those dependencies or use seeded randomness. Deterministic means: same input, same result, every time.

Test behavior, not implementation. A test that asserts "the function called these three internal methods in this order" breaks when you refactor. A test that asserts "given this input, the output is correct" survives refactoring. Test what the code does, not how it does it.

Shift left. Find bugs as early in the pipeline as possible. A bug caught by a unit test (seconds) is cheaper than a bug caught in code review (hours), which is cheaper than a bug caught in staging (days), which is cheaper than a bug caught in production (weeks + customer impact). Every stage later costs roughly 10x more.

Mutation testing. The meta-test: automatically modify your source code (change a + to a -, flip a condition, remove a line) and verify that your tests catch the mutation. If a mutation survives (tests still pass), your tests have a blind spot. Tools: Stryker (JS), mutmut (Python), pitest (Java).

Tools by Layer

Unit & Integration

Jest (JS/TS), Vitest (Vite-native), pytest (Python), go test (Go), XCTest (Swift), JUnit (Java), flutter_test (Dart)

E2E / Browser

Playwright (recommended — fast, reliable, multi-browser), Cypress (popular, good DX), Selenium (legacy but universal), Puppeteer (Chrome-only)

API / Contract

Pact (contract testing), Postman/Newman (API testing), Hurl (HTTP file-based testing), dredd (API Blueprint/OpenAPI)

Performance

k6 (modern, scriptable, Grafana-integrated), Locust (Python-based), Artillery (Node.js), Apache JMeter (legacy but powerful)

Chaos

Chaos Monkey (Netflix, AWS), Litmus (Kubernetes), Gremlin (commercial), toxiproxy (network fault injection)

Static Analysis

ESLint (JS/TS), Ruff (Python), SwiftLint, golangci-lint, SonarQube (multi-language), TypeScript strict mode

Mutation

Stryker (JS/TS), mutmut (Python), pitest (Java/Kotlin)

Voices to Follow

People and channels at the cutting edge of testing and quality engineering:

Kent C. DoddsWeb / YouTube

Creator of Testing Library and the Testing Trophy model. The most influential voice in modern JavaScript testing. His "Testing JavaScript" course is the gold standard.

martinfowler.com has definitive articles on test pyramids, continuous integration, and testing strategies. Dense but authoritative. Read "TestPyramid" and "IntegrationTest" first.

Context-driven testing school. Challenge the assumption that testing is just automation. Their work on exploratory testing and sapient testing is essential for QA professionals.

CEO of Honeycomb, champion of observability over traditional monitoring. Her take: testing in production (with observability) catches classes of bugs that pre-production testing never will.

Continuous Delivery channel. Deep dives into TDD, CI/CD, deployment strategies, and testing in pipelines. Practical, opinionated, and experienced.

Playwright (Official)YouTube / Docs

Microsoft's E2E testing framework is rapidly becoming the standard. Their docs and video tutorials are excellent for getting started with browser testing.

The largest testing community. Articles, courses, meetups, and conferences. If testing is your focus, this is your professional home.

The One Rule

If you remember nothing else from this page, remember this: test at the boundaries, trust the internals, and never paper over a failure.

Boundaries are where bugs live. Internals are where frameworks and languages provide guarantees. Papering over failures (catching exceptions silently, returning default values for missing data, retrying forever without alerting) is how small problems become production incidents. Let failures be loud. Fix them at the source.