Flutter自定义匹配查找插件finder_matcher_gen的使用
Flutter自定义匹配查找插件finder_matcher_gen的使用
动机 ✨
我发现自己在编写自定义的查找器(Finder)和匹配器(Matcher)来抽象化小部件测试中的验证代码。实现这些功能可能会很繁琐。
Finder-Matcher-Gen尝试通过为这些自定义类生成代码来解决这个问题。
前 | 后 | |
---|---|---|
查找器 | ![]() |
![]() |
匹配器 | ![]() |
![]() |
安装 💻
为了开始使用Finder Matcher Gen,必须在你的机器上安装Dart SDK。
在pubspec.yaml
文件中添加finder_matcher_gen
:
运行以下命令:
flutter pub add finder_matcher_annotation
flutter pub add finder_matcher_gen --dev
flutter pub add build_runner --dev
或者手动添加到你的pubspec.yaml
文件。
dependencies:
finder_matcher_annotation: ^[version]
dev_dependencies:
finder_matcher_gen: ^[version]
build_runner: ^[version]
运行以下命令进行安装:
flutter pub get
将以下代码复制粘贴到你的测试文件中以导入:
import 'package:finder_matcher_annotation/finder_matcher_annotation.dart';
注解使用 🚀
Finder-matcher-gen 使用注解声明来生成代码。该工具提供了两个注解:@Match
和 [@MatchDeclaration](/user/MatchDeclaration)
注解。
@Match
注解
将 @Match
注解应用到一个声明(通常是在测试的 main()
函数)中,以指定要生成查找器或匹配器的小部件。
@Match(finders: [], matchers: [])
void main() {
// 测试代码
}
@Match
注解接受两个参数:一个用于查找器的 Type
列表;一个用于匹配器的 MatchWidget
列表。
查找器
对于名为 TrafficLightLampWidget
的小部件,将小部件类型传递给 @Match
注解的 finders
参数以生成查找器对应物。
@Match(finders: [TrafficLightLampWidget])
注意: 可以传递任意数量的小部件类型到 finders
参数以生成查找器对应物。
匹配器
将 MatchWidget
列表传递给 matchers
参数。MatchWidgets
接受三个参数:
- 必需的
type
:此小部件的运行时表示,用于生成匹配器对应物。 - 必需的
matchSpecification
:一个MatchSpecification
枚举,用于定义要为该小部件生成的匹配器类型。 - 可选的
secondaryType
:另一个小部件的运行时表示,该匹配器将使用。
@Match(matchers: [
MatchWidget(TrafficLightLampWidget, MatchSpecification.matchesOneWidget),
])
有关可以设置的不同匹配规范,请点击这里了解更多信息。
[@MatchDeclaration](/user/MatchDeclaration)
注解
在大多数情况下,小部件中定义的声明(获取器、字段、函数)对小部件的身份至关重要。换句话说,它们将用于断言该小部件的行为。
使用 [@MatchDeclaration](/user/MatchDeclaration)
注解标记小部件字段、获取器或函数,以将其标记为在验证代码中使用。[@MatchDeclaration](/user/MatchDeclaration)
注解接受一个 defaultValue
参数,用于与测试环境中找到的实际值进行比较。如果未提供默认值,则将为此声明添加构造函数字段。
class RedTrafficLightLampWidget extends StatelessWidget{
[@MatchDeclaration](/user/MatchDeclaration)()
final Color lightColor;
[@MatchDeclaration](/user/MatchDeclaration)(defaultValue: 'STOP')
final String text;
}
下面的代码展示了提供默认值和不提供默认值的结果。
/// 其中 `_lightColor` 是此生成代码的构造函数字段
return widget.lightColor == _lightColor && widget.text == 'STOP';
静态分析
在使用此注解时,常见的错误是传递了错误的数据类型(不同于注解属性的数据类型)给 defaultValue
。
幸运的是,此包提供了静态分析,可以在发生此类错误时抛出异常。
注意: [@MatchDeclaration](/user/MatchDeclaration)
注解只能用于获取器、字段和非空方法。
生成代码 🏭
运行以下命令以生成自定义查找器和匹配器代码。
flutter pub run build_runner build
成功运行后,你应该会注意到两个新生成的文件:
- 包含生成查找器的文件
<my_test_file>.finders.dart
- 包含生成匹配器的文件
<my_test_file>.matchers.dart
有关更多信息,请参阅生成部分以了解如何使用生成的文件。
为集成测试配置生成
在项目的顶级文件夹中创建一个 build.yaml
文件。在新创建的文件中插入以下代码。
targets:
$default:
sources:
- integration_test/**
- lib/**
- test/**
# 注意,包括这些在默认目标中很重要。
- pubspec.*
- $package$
注意: 你还可以包含需要生成匹配器和查找器的自定义文件夹。
详细文档 📄
有关使用此工具的更多详细信息,请访问文档。
Bug/请求 🐛
如果你遇到任何问题,请随时打开一个问题。如果你觉得库缺少功能,请在Github上提出一个建议,我会考虑它。也欢迎提交拉取请求。
持续集成 🤖
Finder Matcher Gen 配备了一个由 Very Good Workflows 支持的 GitHub Actions 工作流,但你也可以添加自己的 CI/CD 解决方案。
开箱即用,在每个拉取请求和推送时,CI 会格式化、检查和测试代码。这确保了代码的一致性和正确性。该项目使用 Very Good Analysis 进行严格的分析选项。使用 Very Good Workflows 执行代码覆盖率。
示例代码
example/lib/main.dart
import 'package:example/models.dart';
import 'package:example/widgets.dart';
import 'package:finder_matcher_annotation/finder_matcher_annotation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
useMaterial3: true,
primarySwatch: Colors.blue,
sliderTheme: const SliderThemeData(
trackHeight: 10,
),
),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
[@override](/user/override)
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final tasks = <TaskModel>[];
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: const Text('Tasks')),
body: tasks.isEmpty
? Center(
child: Padding(
padding: const EdgeInsets.all(32.0).copyWith(bottom: 100),
child: const Text(
"Your task list is empty. Tap on the 'Add Task' button to add a task.",
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 16,
),
),
),
)
: TaskListView(tasks: tasks),
floatingActionButton: AppFloatingActionButton(
onPress: () async {
final newTask = await showModalBottomSheet(
context: context,
builder: (c) => const AddTargetBottomSheet(),
);
if (newTask != null) {
tasks.add(newTask);
setState(() {});
}
},
),
);
}
}
class TaskListView extends StatelessWidget {
const TaskListView({
Key? key,
required this.tasks,
}) : super(key: key);
[@MatchDeclaration](/user/MatchDeclaration)()
final List<TaskModel> tasks;
[@override](/user/override)
Widget build(BuildContext context) {
return ListView.builder(
itemCount: tasks.length,
itemBuilder: (context, index) => ItemTask(taskModel: tasks[index]),
physics: const BouncingScrollPhysics(),
);
}
}
更多关于Flutter自定义匹配查找插件finder_matcher_gen的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter自定义匹配查找插件finder_matcher_gen的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何使用Flutter中的finder_matcher_gen
插件进行自定义匹配查找的示例代码。这个插件通常用于自动生成用于查找Widget的匹配器,从而简化测试代码。
首先,确保你已经在pubspec.yaml
文件中添加了finder_matcher_gen
依赖:
dependencies:
flutter:
sdk: flutter
test: ^1.16.0 # 确保你有合适的test包版本
dev_dependencies:
build_runner: ^1.0.0 # 用于生成代码
finder_matcher_gen: ^x.y.z # 替换为最新版本号
然后,你需要创建一个用于定义匹配器的YAML文件。例如,创建一个名为matchers.yaml
的文件:
matchers:
myCustomButton:
type: ByType
value: ElevatedButton
child:
type: ByText
value: My Button Text
接下来,在你的Flutter项目中,运行以下命令来生成匹配器代码:
flutter pub run build_runner build
这会在你的项目中生成一个matchers.g.dart
文件,其中包含了基于matchers.yaml
定义的匹配器。
现在,你可以在测试代码中使用这些生成的匹配器。例如,创建一个名为my_widget_test.dart
的测试文件:
import 'package:flutter_test/flutter_test.dart';
import 'package:your_app/matchers.g.dart'; // 导入生成的匹配器文件
import 'package:your_app/main.dart'; // 导入你的应用主文件
void main() {
testWidgets('finds my custom button', (WidgetTester tester) async {
await tester.pumpWidget(MyApp()); // 加载你的应用
// 使用生成的匹配器查找Widget
expect(find.byType(MyCustomButtonMatcher), findsOneWidget);
});
}
请注意,上面的代码中MyCustomButtonMatcher
是从matchers.g.dart
文件中生成的匹配器类。这个类是根据matchers.yaml
文件中定义的规则生成的,用于匹配具有特定属性的ElevatedButton
。
完整的流程如下:
- 定义匹配规则(
matchers.yaml
)。 - 运行
flutter pub run build_runner build
生成匹配器代码。 - 在测试代码中使用生成的匹配器。
这个示例展示了如何使用finder_matcher_gen
插件来简化和标准化Widget查找,使得测试代码更加清晰和易于维护。