Adopt two-layer iOS testing
Context
We want good coverage so we can move fast, but not tests that overlap and create maintenance work. LLMs make generating tests trivial now, so the problem isn't writing enough tests — it's deciding what to test where, so you don't end up with four layers all catching the same bug differently.
Point-Free's "Testing SwiftUI" argues for two distinct layers rather than the typical four (unit, integration, UI automation, snapshot). That matched what we needed.
Integration tests would be ideal but the iOS story for them isn't great — running end-to-end tests through the Xcode simulator is clunky compared to web tooling like Cuprite. Rather than adopt something brittle, we left that layer out for now.
Decision
Two layers, nothing else:
Unit tests for behavior — business logic, state management, data flow. Services, models, Apollo integration. Tested with XCTest and mocked dependencies. No UI interaction testing — test state directly instead.
Snapshot tests for layout — visual regression across device configurations (iPhone SE through iPad Pro 12.9"). Tested with swift-snapshot-testing. Captures static layouts, not animations or loading states.
Consequences
Fast test execution with no UI automation overhead. Each layer has a single purpose, so failures point clearly at either a logic bug or a layout regression.
The gap is complex user journeys — multi-step flows need careful unit test design since there's no integration layer covering end-to-end scenarios. Snapshot reference images also need updating when UI changes are intentional.