Assertions in Dart and Flutter tests: equality matchers
This is the part of the ultimate cheat sheet dedicated to:
- matcher
equals
, - equality matchers.
In this series:
- expect and matcher
- equality matchers
- type and error matchers
- collection matchers
- numeric and comparable matchers
- universal and custom matchers
- matcher operators
- asynchronous expect and matchers
- Flutter widget matchers
- accessibility matchers
- golden matchers
- mock invocations and parameters
Matcher equals
In the example below, we pass 0
as a matcher
parameter:
test('expect: value β
', () {
final result = 0;
expect(result, 0);
});
In such a case, when the value is passed, an equals
matcher is used implicitly. It is equivalent to:
test('matcher: equals β
', () {
final result = 0;
expect(result, equals(0));
});
It is probably the most commonly used matcher, explicitly or implicitly.
The equals
matcher uses the equality operator to perform the comparison. By default, classes in Dart are compared βby referenceβ and not βby valueβ. Thus, if applied to custom objects like this Result
class here:
class Result {
Result(this.value);
final int value;
}
equals
matcher fails this test:
test('expect: equals β', () {
final result = Result(0);
expect(result, equals(Result(0)));
});
with the following output:
Expected: <Instance of 'Result'>
Actual: <Instance of 'Result'>
It is a good idea to override the .toString()
method to make the output more meaningful. For this improved Result
class implementation:
class Result {
Result(this.value);
final int value;
@override
String toString() => 'Result{value: $value}';
}
the test output changes to:
Expected: Result:<Result{value: 0}>
Actual: Result:<Result{value: 0}>
To make it pass, the Result
class has to override the operator ==
, for example like this:
class Result {
Result(this.value);
final int value;
@override
String toString() => 'Result{value: $value}';
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Result &&
runtimeType == other.runtimeType &&
value == other.value;
@override
int get hashCode => value.hashCode;
}
Equality matchers
same
The same
matcher makes sure expected and actual results are exactly the same instance. This test:
test('expect: same β', () {
final result = Result(1);
expect(result, same(Result(1)));
});
fails with the following output:
Expected: same instance as Result:<Result{result: 1}>
Actual: Result:<Result{result: 1}>
But this test passes:
test('expect: same β
', () {
final result = Result(1);
expect(result, same(result));
});
Interesting observation regarding const
. This test also passes:
test('expect: same β
', () {
final result = 1;
expect(result, same(1));
});
because 1
is a const
and only one instance exists in memory. The same applies when custom classes declare const
constructors and instances are created with const
modifier. If the Result
class is updated to declare a const
constructor:
class Result {
const Result(this.value);
final int value;
}
this test also passes:
test('expect: same β
', () {
final result = const Result(1);
expect(result, same(const Result(1)));
});
But this test still fails:
test('expect: same β', () {
final result = Result(1);
expect(result, same(Result(1)));
});
because without using const
, two different instances of Result
are created.
null matchers
The next pair of matchers is quite simple: isNull
and isNotNull
check result
nullability.
test('expect: isNull β', () {
final result = 0;
expect(result, isNull);
});
fails with:
Expected: null
Actual: <0>
And this test passes:
test('expect: isNotNull β
', () {
final result = 0;
expect(result, isNotNull);
});
bool matchers
The next pair of equality matchers is self-explanatory: isTrue
and isFalse
. These tests pass:
test('expect: isTrue β
', () {
final result = 0;
expect(result < 1, isTrue);
});
test('expect: isFalse β
', () {
final result = 0;
expect(result > 1, isFalse);
});
anything
The anything
matcher matches literally any value. It is used in any
from mockito package or any<T>()
from mocktail, which weβll discuss in another part. However, itβs not a commonly used matcher in client application tests.
Originally published at Invertase blog. Check out their awesome Authors Program!
Hi! ππ» Iβm Anna, Google Developer Expert in Flutter from Ukraine πΊπ¦ Follow me on Twitter, GitHub, YouTube, Medium to get notifications about my latest work.
Itβs early 2023, and we in Ukraine are still fighting against russians committing genocide on our lands. If you find this content useful and have a coin to spare, support us with your donations. Stand with Ukraine!