Skip to content

Flutter Feature Tests: Repository, Widget, and Device Responsibilities

Putting every check in an end-to-end suite makes failures slow to locate. Testing only a ViewModel misses disabled buttons, hidden errors, and inaccessible controls. Choose the test layer according to the boundary that can fail.

Give each layer a job ​

Repository unit tests cover cache fallback, error mapping, offline queues, and version conflicts with a fake clock and controlled network. Widget tests assert that old orders remain visible during refresh, empty states offer creation, and permission errors disable actions. Inject a fake repository rather than a live server. Keep only a few integration paths: login, order creation, offline recovery, and synchronization.

Make failures deterministic ​

Use fixed IDs and timestamps so ordering bugs are visible. Wait for a defined state instead of sleeping a fixed number of seconds. Screenshot tests can protect stable key layouts, but pixel equality is not a substitute for behavior assertions. Fonts, scaling, and platform rendering can all change pixels.

Run a small device matrix for navigation, platform permissions, and persistence; keep exhaustive state transitions in fast lower-level tests. See the Flutter testing overview.

Build a test mix around one transfer ​

A transfer includes amount validation, recipient lookup, a confirmation screen, submission, and a result screen. Keep amount limits, currency precision, balances, and fee calculations in pure logic outside widgets, with unit tests for boundary and rounding cases; these are cheap enough to run on every change. Then use widget tests for input errors, loading, confirmation, and recovery, injecting a fake repository and controllable clock. Do not merely assert that copy appears: check that submit is disabled during a request, re-enabled after failure, and protected from an old response contaminating a new form.

Reserve integration tests for a few critical journeys: sign in, open transfer, confirm the recipient, submit, and find the record. Use a controlled test backend or clearly identified simulator with isolated accounts and data; a real-money network does not belong in CI. System keyboards, permission prompts, deep-link return, and background transitions still need a pass in the actual target runtime. Widget tests cannot substitute for those OS interactions.

LayerMain questionExample assertion
UnitAre rules correct?Currency precision, fees, amount boundaries
WidgetCan UI state recover?No duplicate submit; retry after failure
IntegrationDo parts cooperate?One submission yields one server record
Device acceptanceDoes OS behavior fit?Keyboard, resume, weak network

Keep test doubles from hiding races ​

A fake repository should let tests resolve requests in a chosen order rather than always succeeding immediately. Cover competing submissions, a response after leaving the page, server timeout after actual success, and duplicate navigation to a result page. The server's idempotent outcome determines whether a request succeeded; a test's assumed navigation count does not. See Flutter testing overview.

MIT Licensed