Flutter模式匹配插件matcher的使用
Flutter模式匹配插件matcher的使用
简介
matcher
是一个用于指定测试期望(如单元测试)的支持包。它提供了一套第三代断言机制,灵感来源于 Hamcrest。通过 matcher
,可以编写更具表达力和可读性的测试代码。
更多关于测试的信息,请参阅 Unit Testing with Dart。
使用 matcher
基本用法
所有的期望都以调用 expect()
或 expectAsync()
开始。可以使用任何 matchers 包与 expect()
结合来进行复杂的验证:
import 'package:test/test.dart';
void main() {
test('.split() splits the string on the delimiter', () {
expect('foo,bar,baz', allOf([
contains('foo'),
isNot(startsWith('bar')),
endsWith('baz')
]));
});
}
如果传递的是非 matcher 的值,它将被 equals()
包装。
异常匹配器
可以使用 throwsA()
函数或类似 throwsFormatException
的 matcher 来测试异常:
import 'package:test/test.dart';
void main() {
test('.parse() fails on invalid input', () {
expect(() => int.parse('X'), throwsFormatException);
});
}
Future 匹配器
对于更高级的异步操作,matcher
提供了多种有用的函数和 matcher。completion()
matcher 可以用来测试 Future
;它确保测试不会在 Future
完成之前结束,并对 Future
的值运行 matcher。
import 'dart:async';
import 'package:test/test.dart';
void main() {
test('Future.value() returns the value', () {
expect(Future.value(10), completion(equals(10)));
});
test('Future.error() throws the error', () {
expect(Future.error('oh no'), throwsA(equals('oh no')));
expect(Future.error(StateError('bad state')), throwsStateError);
});
}
Stream 匹配器
test
包提供了强大的 matcher 来处理 异步流。这些 matcher 表达力强且可组合,使得编写关于流发出值的复杂期望变得简单。
例如:
import 'dart:async';
import 'package:test/test.dart';
void main() {
test('process emits status messages', () {
var stdoutLines = Stream.fromIterable([
'Ready.',
'Loading took 150ms.',
'Succeeded!'
]);
expect(stdoutLines, emitsInOrder([
'Ready.',
startsWith('Loading took'),
emitsAnyOf(['Succeeded!', 'Failed!']),
emitsDone
]));
});
}
流 matcher 还可以匹配 async
包的 StreamQueue
类,允许从流中请求事件而不是推送给消费者。
import 'dart:async';
import 'package:async/async.dart';
import 'package:test/test.dart';
void main() {
test('process emits a WebSocket URL', () async {
var stdout = StreamQueue(Stream.fromIterable([
'WebSocket URL:',
'ws://localhost:1234/',
'Waiting for connection...'
]));
await expectLater(stdout, emitsThrough('WebSocket URL:'));
var url = Uri.parse(await stdout.next);
expect(url.host, equals('localhost'));
await expectLater(stdout, emits('Waiting for connection...'));
});
}
内置的流 matcher 包括:
emits()
:匹配单个数据事件。emitsError()
:匹配单个错误事件。emitsDone
:匹配单个完成事件。mayEmit()
:如果匹配内部 matcher,则消耗事件。mayEmitMultiple()
:尽可能多次匹配事件。emitsAnyOf()
:匹配多个可能的 matcher 中的一个或多个。emitsInOrder()
:按顺序匹配多个 matcher。emitsInAnyOrder()
:以任意顺序匹配多个 matcher。neverEmits()
:匹配在没有匹配内部 matcher 的情况下完成的流。
还可以使用 StreamMatcher()
定义自定义流 matcher。
最佳实践
优先使用语义上有意义的 matcher 而不是比较派生值
具有测试知识的 matcher 可以生成更有意义的消息,不需要阅读测试源码就能理解测试失败的原因。例如,比较 expect(someList.length, 1)
和 expect(someList, hasLength(1))
的失败信息:
// expect(someList.length, 1);
Expected: <1>
Actual: <2>
// expect(someList, hasLength(1));
Expected: an object with length of <1>
Actual: ['expected value', 'unexpected value']
Which: has length of <2>
优先使用 TypeMatcher 而不是 predicate,如果匹配可以有多种失败方式
predicate
工具是测试任意(同步)值属性的便捷快捷方式,但它会丢弃上下文,失败信息不透明。不同的失败模式无法在输出中区分,因为输出由单一的 “description” 参数决定。使用 isA<SomeType>()
和 TypeMatcher.having
API 以结构化的方式提取和测试派生属性,可以将该结构的上下文带入失败消息,从而使不同原因的失败消息可区分且可操作。
以上就是 matcher
插件在 Flutter 中的使用方法和一些最佳实践。希望对你有所帮助!
更多关于Flutter模式匹配插件matcher的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html