Assertions in Dart and Flutter tests: an ultimate cheat sheet
Whether you are creating unit, widget, or integration tests for Flutter applications, the end goal of any test is asserting that the reality matches the expectations. Here is an ultimate cheat sheet for assertions in Dart and Flutter tests with many details explained!
10 min readTests are essential for ensuring any software quality. Whether you are creating unit, widget, or integration tests for Flutter applications, the end goal of any test is asserting that the reality matches the expectations. Here is an ultimate cheat sheet for assertions in Dart and Flutter tests with many details explained!
Cheat sheet

The previous post covered a significant part of checks you can perform in Flutter and Dart tests and explained more than half of this cheat sheet in detail. Here we focus on the bottom half, starting with asynchronous matches.
Before you start, you can read all tests in the following Zapp.run project.
Asynchronous expect

The expectLater() function is just like expect(), but returns a Future that completes when the matcher has finished matching.
While expectLater() can accept any matcher, it makes sense to pass children of AsyncMatcher class, which does asynchronous computation.
Future matchers

There are a few matchers to test Future execution results.
The completes matcher completes successfully when the Future completes successfully with any value.
The completion matcher accepts the matcher to verify the Future result:
And the throwsA matcher should be already familiar:
Stream matchers
First, we’ll focus on testing streams with hardcoded values to see the variety of stream matchers. And then, we’ll have a word about testing streams when it’s too late to use the expect() function.

emits / neverEmits
The emits matcher checks that the Stream has emitted a value that satisfies a matcher, that emits has been accepted as a parameter. It may accept the expected value, another matcher that characterizes the expected value, or a predicate function:
The neverEmits matcher performs the opposite check:
emitsInOrder / emitsInAnyOrder
These matchers ensure a stream has emitted multiple events.
In particular order:
Or in no particular order:
As you see, both accept an array, containing expected values or matchers.
emitsDone
The emitsDone matcher helps ensure a stream does not emit any more unexpected values:
emitsError
The emitsError matcher helps ensure a stream has emitted an error and accepts another matcher to verify the exact error:
Testing closed / drained streams
So far we tested streams that contained hardcoded values, which were emitted immediately inside the expect() function. But imagine, we have to test a stream that was already closed or a stream that has already emitted values we are interested in.
Let’s take a look at this class:
When doWork method is called, the stream should emit two values: 0 and 1. Here is a test that comes to mind for this behavior:
Unfortunately, the expect() function is called too late, emitted values are already gone, and this test never completes. Instead, expect() or expectLater() should be used before doWork() call.
Unlike using expectLater() with Future matchers, where it is placed at the end of the test and is awaited, for testing StreamMatcher, it should be placed before performing the calls that affect stream values. This way, we can catch values as the stream emits them. In such a case, the expectLater() call should not be awaited, otherwise, the test will not be complete as well.
Flutter widgets matchers
Flutter widget tests use the same expect() method to verify the actual widget tree content matches expectations. However, the list of matchers is unique to this task.

No / One / N widgets matchers
This group of matchers is the most commonly used in Flutter widget tests.
findsNothing ensures no widget in the widget tree matches the first parameter of the expect() method:
The findsWidgets/findsOneWidget matchers ensure at least/exactly one widget is present in the tree:
In the example above, findsOneWidget matcher failed the test because the widget tree contains two widgets with the text '1'. The test output is:
The findsAtLeastNWidgets/findsNWidgets matchers ensure at least/exactly N widgets are present in the widgets tree.
Color matcher
isSameColorAs helps verify properties of Color type of any widget:
Parent matchers
isInCard/isNotInCard helps to verify that widget has at least one/no Card widget ancestor:
Error matchers
We all know that the Container widget cannot accept both color and decoration parameters because of the following assert in its constructor:
If you take a similar approach when implementing your widgets, the throwsAssertionError matcher can help with testing these asserts:
Because throwsAssertionError uses throwsA matcher under the hood, the same principle applies here: the function that is expected to throw should be called under the expect() method call.
The throwsFlutterError matcher verifies that a function throws FlutterError. Here is an example from the Flutter framework tests:
Accessibility matchers

There is only one pair of accessibility matchers: meetsGuideline/doesNotMeetGuideline. These matchers are asynchronous, and thus should be used with the expectLater assertion function mentioned before.
They accept AccessibilityGuideline object, which represents the type of performed accessibility check. There are several predefined guidelines to check against:
androidTapTargetGuidelinechecks that tappable nodes have a minimum size of 48 by 48 pixels;iOSTapTargetGuidelinechecks that tappable nodes have a minimum size of 44 by 44 pixels;textContrastGuidelineprovides guidance for text contrast requirements specified by WCAG;labeledTapTargetGuidelineenforces that all nodes with a tap or long press action also have a label.
Your own guidelines can be created by inheriting AccessibilityGuideline class or creating your own instances of MinimumTapTargetGuideline, MinimumTextContrastGuideline, LabeledTapTargetGuideline.
Let’s take a look at this example:
The GestureDetector will have a size of 46×46, which is just enough to satisfy the iOSTapTargetGuideline which requires 44×44 tap area. A similar test that uses androidTapTargetGuideline, which requires a 48×48 tap area, fails:
with the following output:
Let’s check an example using textContrastGuideline:
Black text on white background has a good contrast ratio, so this test passes. However, small orange text on a white background is hard to read, and this test fails:
with the following output:
As you see, the output mentions that the expected contrast ratio depends on the font size. In the example above, when no text style was provided in Text widget, nor in MaterialApp, the default text size of 14 was applied. Interestingly enough, if the text font is increased, the same test passes because larger texts are easier to read even when the contrast ratio is not perfect:
Golden matchers

Image file matcher
The matchesGoldenFile matcher allows validating that a Finder, Future<ui.Image>, or ui.Image matches the reference (golden) image file:
Image object matcher
The matchesReferenceImage matcher allows validating that a Finder, Future<ui.Image>, or ui.Image matches the reference ui.Image object:
For testing a Finder, as in the test above, it must match exactly one widget and the rendered image of the first RepaintBoundary ancestor of the widget is treated as the image for the widget.

Mock invocations and parameters
So far, we have used expect() function to compare the results of some operations with the expected values. There is another category of checks developers constantly perform: ensuring that some side effect was triggered.
Verify invocations

For that, the verify() function is used:
This verify() function comes from the mocktail package. The mockito package provides similar functionality.
For context, here is the definition of MockService:
The verify() function ensures that provided method was called at least once. The test above fails because the sideEffect() method was never called, with the following output:
To ensure certain method was called exactly N times, use the called() method of verify() function result:
To ensure certain method was never called, use the verifyNever() function:
Verify parameters

In the example above, the sideEffect() method accepts two parameters. In case their values do not matter, use the any() object that can represent literally any value:
In case of invocation parameters matter, real values can be used instead of any():
Similar to equals matcher, verify will compare parameters using the equality operator. Thus, for the above test to pass, the Result class has to have the operator == overridden, as was shown before. Otherwise, the test fails with the following output:
In case you are only interested in checking those parameters met some condition, any() call can accept one of the matchers we looked so closely at before as that parameter:

This post concludes the topic of assertions available in Dart and Flutter tests.
Follow Anna on social media to get notifications about her latest work!
Stay tuned for more updates and exciting news that we will share in the future. Follow us on Invertase Twitter, Linkedin, and Youtube, and subscribe to our monthly newsletter to stay up-to-date. You may also join our Discord to have an instant conversation with us.