Software Testing, From First Principles
This course is built around a single throughline: how do you earn justified confidence that software works — and how do you think about the edge cases that break it? You can never prove software is bug-free — the inputs are effectively infinite — so testing is not about proof. It is about buying confidence cheaply and finding where things break before your users do. Every part below serves that one question.
How to read this: go in order — each part builds on the ideas before it. At the end of each page, answer the Check-your-understanding questions in your own words before moving on; that is where the ideas actually stick. Optimize for depth over speed: it is better to truly understand one part than to skim five.
Foundations — Why We Test
- Overview
- The Infinite Input Space
- Justified Confidence
- The Cost of a Bug
- Verification and Validation
- Quality, Testing, and QA
- The Oracle Problem
- How Much Is Enough?
- Revision
Thinking Like a Tester
- Overview
- The Adversarial Mindset
- Happy Path vs. Sad Path
- Zero, One, Many
- Empty, Null, and Boundaries
- Extremes, Overflow, and Invalid Input
- Ordering and Duplicates
- Exploratory Testing
- Revision
Test Design Techniques
- Overview
- Equivalence Partitioning
- Boundary Value Analysis
- Decision Tables
- State Transition Testing
- Pairwise / Combinatorial Testing
- Error Guessing and Experience
- Combining Techniques
- Revision
Levels of Testing
- Overview
- Unit Tests
- Integration Tests
- System and End-to-End
- Acceptance Tests
- Pyramid vs. Trophy
- Composing a Strategy
- Revision
Unit Testing
- Overview
- What Is a Unit, and AAA
- The FIRST Properties
- Pure vs. Impure Code
- Test Doubles
- Isolating Dependencies
- Tests as Living Documentation
- Revision
Integration & End-to-End Testing
- Overview
- Integration Strategies
- Contract Testing
- Real vs. Fake Dependencies
- End-to-End Tests
- Flaky Tests: Causes
- Flaky Tests: Cures
- Revision
Types of Testing
- Overview
- Functional Testing
- Regression, Smoke, and Sanity
- Performance, Load, Stress, and Soak
- Security Testing Basics
- Accessibility, Usability, and Compatibility
- Exploratory Testing
- Choosing What to Test
- Revision
Test Automation
- Overview
- What to Automate
- The Pyramid Revisited
- Frameworks and Runners
- Page Object and UI Patterns
- Data-Driven Tests
- CI and Keeping Green
- Revision
TDD & BDD
- Overview
- Red, Green, Refactor
- Test-First Changes Design
- TDD Benefits and Criticisms
- BDD and Gherkin
- Example vs. Property
- Writing Properties
- Shrinking and Edge Cases
- Revision
Coverage & Quality Metrics
- Overview
- What Coverage Measures
- Coverage Types
- Why 100% Is Not Bug-Free
- Mutation Testing
- Defect Metrics
- Goodhart’s Law
- Revision
Edge Cases — A Field Guide
- Overview
- Numbers and Arithmetic
- Strings and Text
- Collections and Ordering
- Dates and Times
- Null, Optional, and Absence
- Concurrency and Races
- Resources, Network, and Trust
- Revision
Testing in Practice
- Overview
- Test Environments and Configuration
- Managing Test Data
- Determinism: Time, Randomness, Order
- Debugging a Failing Test
- Writing a Bug Report That Gets Fixed
- Working with Developers
- Test Maintenance and Test Debt
- Revision
Frontier — Fuzzing, Chaos & AI
- Overview
- Coverage-Guided Fuzzing
- Fuzzing vs. Property Testing
- Chaos Engineering
- AI-Assisted Testing
- Testing ML Systems: No Oracle
- Data Drift and Monitoring
- Revision
Hands-On — Test a Feature End to End