Skip to content

About

A GoF-style catalog of unit testing patterns — language-independent ideas, reference implementation in Dart/Flutter with 127 runnable tests.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

18 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Flutter Unit Testing Catalog

A catalog of unit testing patterns, structured in the spirit of the Gang of Four Design Patterns. Reference implementation in Dart and Flutter.

Introduction → · Catalog Index ↓ · Glossary →

Every entry is a self-contained chapter with prose and runnable Dart tests. Pick a pattern below, or read the introduction first.


The Idea Behind This Book

Every method call is a message. An object receives a message, does something with it, and the world changes — or does not. Three things can happen when a method is called: it can return a value, it can change internal state, or it can send messages to other objects. Everything in unit testing flows from these three primitives.

This catalog names each pattern, explains the problem that arises without it, and shows the solution in a reference implementation — Dart and Flutter, production class first, test second. The patterns themselves are language-independent: the same catalog could be written in Swift, Kotlin, or C# by rewriting only the code and the Implementation Notes (see A Note on Language). Like the Gang of Four, each entry stands alone. Read them in order or jump to what you need from the Catalog Index below.

The core idea builds on earlier work, most directly Sandi Metz's message-based approach to testing and Gerard Meszaros's xUnit Test Patterns. The Introduction credits both.


Catalog Index

Click any chapter to open its pattern — prose, production code, and tests.

Foundations

# Chapter
— Introduction: The Message Metaphor

Core Message Patterns

# Chapter Subject
1 Receiving a Message and Responding MessageFormatter — relative-time labels, message previews
2 Changing State UnreadCounter — badge on a conversation row
3 Sending Out More Messages ChatManager.sendMessage calling analytics
4 Side Effects — Completeness of Outgoing Calls ChatManager.sendMessage — persist, observe, log

Reliability Patterns

# Chapter Subject
5 Exceptions & Error Handling Nine error-handling patterns (E1–E9) on ChatManager
— ↳ E1: Exception Throwing
— ↳ E2: Exception Types
— ↳ E3: Error Messages
— ↳ E4: Exception Handling
— ↳ E5: State After Exception
— ↳ E6: Fallback Mechanisms
— ↳ E7: Input Validation
— ↳ E8: Boundary Conditions
— ↳ E9: Resource Cleanup
6 Adversarial Inputs ChatManager.receiveMessage — out-of-order timestamps
7 Initial State and Setup ChatManager loading message history
8 Concurrency and Timing Concurrent sends + delivery receipts
9 Idempotence Dedup by stable clientMessageId

Specialized Patterns

# Chapter Subject
10 Memory and Resource Management IncomingMessageBinder — stream subscriptions
11 Third-Party Integration ChatService wrapping a backend HTTP client
12 Fallbacks and Redundancies MessageRepository — remote + cache + placeholder
13 Performance and Timing TypingIndicator — debounced "stopped typing"
14 Security and Input Validation MessageSanitizer — markup stripping + HTML entity encoding
15 State Transitions MessageDelivery lifecycle

All chapters share the same imagined chat app as their running example, so the catalog reads as one story. Each chapter's code/ folder is self-contained — no cross-chapter imports required.


How to Read This Catalog

Every chapter follows the same GoF-inspired structure. If you encounter a term you do not recognise, the Glossary defines every key word used in this catalog.

Section Purpose
Intent One sentence: what this test pattern verifies
The Problem The scenario that hurts without this pattern
Forces The tensions you are navigating
Solution The pattern in prose, followed by Dart code
Consequences What you gain and what you give up
Implementation Notes Dart/flutter_test-specific tips
Related Patterns Other entries in this catalog

Code for each chapter lives in its code/ subfolder — a production .dart file and a _test.dart file side by side.


Running the Code

This catalog is a Flutter package. The test files live alongside the production code inside each chapter's code/ folder rather than in a top-level test/ directory, so flutter test needs to be pointed at them explicitly.

To run every test in the catalog:

flutter pub get
flutter test $(find . -name "*_test.dart" -not -path "*/build/*")

To run a single chapter's tests:

flutter test chapter01_receiving_responding/code/message_formatter_test.dart

Dependencies are declared in pubspec.yaml. Run flutter pub get once before running tests.


What This Catalog Deliberately Does Not Cover

The patterns in this book are scoped to unit tests for plain Dart classes — the layer where business logic lives. Several adjacent categories of testing are intentionally outside that scope. They are not less important; they answer different questions and use different oracles. Naming them here is meant to set expectations, not to dismiss them.

  • Widget tests (testWidgets) — Tests that mount a widget tree in a simulated rendering environment and verify layout, tap behavior, or accessibility. Every test() call in this catalog operates on a plain class; nothing renders on screen. For the widget layer, see the Flutter widget testing documentation.

  • Golden / snapshot tests — Pixel-level regression tests for rendered widgets. The oracle is an image comparison, not an expect() matcher. These belong in the same suite as widget tests and require the same rendering pipeline.

  • Integration tests (integration_test package) — End-to-end tests that drive a real app on a device or emulator. They verify that the assembled application behaves correctly, not that any individual class fulfills its contract. The patterns in this catalog are about the second question; integration tests answer the first.

  • Property-based testing (e.g. glados) — Generative testing where the framework fabricates inputs to find counterexamples. Complementary rather than excluded: every pattern here could be reinforced with a property-based test. The catalog uses example-based assertions throughout because they are the form most teams write first and most reliably.

  • Test-first vs test-last workflow — Whether tests are written before, after, or alongside production code is a workflow choice. The patterns work regardless. The Introduction discusses this briefly; this catalog takes no position.

  • State-management framework testing (bloc / riverpod / provider / GetX) — Testing notifiers, blocs, and providers requires conventions specific to each framework (e.g. bloc_test's blocTest() helper, ProviderContainer for Riverpod). The general patterns here apply to the classes those frameworks wrap, but framework-specific helpers are not covered.

  • Mocking libraries (mocktail, mockito) — Every test in this catalog hand-writes its stubs and mocks to keep the seam visible. In a real codebase, mocktail removes most of the boilerplate. The patterns translate directly; the syntax changes.


Exception Sub-Catalog Quick Reference

Chapter 5 is itself a mini-catalog. The nine entries in the Catalog Index cover every aspect of testing error handling:

Entry What It Tests Read
E1 That an exception is thrown at all →
E2 That the correct exception type is thrown →
E3 That the exception carries the correct message →
E4 That the calling code handles the exception correctly →
E5 That the object is in a consistent state after an exception →
E6 That a fallback path is taken when the primary path fails →
E7 That invalid inputs are rejected before reaching business logic →
E8 That the system behaves correctly at boundary values →
E9 That resources are released even when an exception occurs →

Unsure how E7 differs from E8? See validation vs boundaries.


Reference

  • Catalog Index — All chapters and patterns
  • Glossary — Definitions for every key term: stub, mock, fake, spy, SUT, observable behavior, and more.
  • License — CC0 1.0 (public domain). Use, copy, adapt, and republish any part of this catalog, text or code, for any purpose. No permission or credit required; a link back is appreciated.
  • Social media assets — Share images for GitHub, Twitter/X, LinkedIn, and square posts

If your classes have hard-coded dependencies and you are not sure how to make them testable before applying the patterns, see Designing for Testability.

About

A GoF-style catalog of unit testing patterns — language-independent ideas, reference implementation in Dart/Flutter with 127 runnable tests.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages