前言
UI测试分为两种类型:行为测试和视觉测试。行为测试主要关注用户在操作UI组件时,UI的变化是否正确。而视觉测试则着重于验证UI的外观是否符合预期。通过比较应用的实际截图与预期结果,视觉测试能够确保UI在不同平台、不同设备上的一致性和美观性。
在实际项目开发中,经常会对现有的UI进行功能扩展或修改。例如,在消息通知按钮上添加红点提示功能。这种改动可能会导致原有的UI出现问题,比如间距不一致或字体大小不对等。而验证是否出现该问题需要不少的成本,如果只是细小的差别,如2,3个像素的差别,那肉眼很难鉴别。这时就需要Golden test了。Golden Test正是一种视觉测试工具,它能够帮助我们确认新功能的引入是否影响了UI的整体外观,从而确保应用的质量和用户体验。
什么是Golden Test
Golden Test
是一种通过比较图片来测试 UI 的技术。它首先创建一个标准图片,表示 UI 正确状态。然后,当开发者对 UI 进行修改时,Golden Test
会自动捕获新的 UI 状态,并与标准图片进行比较。通过比较这两张图片,Golden Test
可以发现 UI 的变化,并生成测试报告。因此,Golden Test
也被称为快照测试,它以像素级别的准确性进行比较,即使是微小的像素差异也能被捕捉到。这使得 Golden Test
在视觉测试方面非常可靠,开发者可以放心地使用它来确保应用在不同情况下的一致性和美观性。
Golden Test 在许多平台中都有对应的工具,如Android中有Paparazzi
,IOS中有SnapshotTesting
, Web中有snapshot-diff
等,不过它们大部分都不是平台官方的工具而是以第三方库的形式存在。而Flutter是少有的提供了Golden Test
官方支持的平台。接下来我将讲述如何在flutter中使用Golden Test
如何使用Golden test
在Flutter 项目中的test文件夹里,创建一个golden_widget_test.dart
的代码文件。代码如下:
dart
void main() {
testWidgets('Golden test', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
await expectLater(find.byType(MyApp),
matchesGoldenFile('circle_button.png'));
});
}
正如你所看到的,我通过tester.pumpWidget
方法渲染一个My App widget ,该widget包含CircleButton
dart
await tester.pumpWidget(MyApp());
然后expectLater
验证该widget是否与基准图片(main.png)一致。
dart
await expectLater(find.byType(MyApp),
matchesGoldenFile('circle_button.png'));
一开始我们并没有基准图片,所以假定当前Widget的UI是正确的,即通过UI设计师验证过的,则通过运行该命令,生成基准图片。
shell
flutter test --update-goldens
运行该命令后,test
文件夹出现了circle_button.png
,这就是基准图片。不过这基准图片似乎不太对,对比运行在真机上按钮的字体变成了矩形。
circle_button.png
真机运行图片
出现这种情况的原因是不同的设备上运行的字体都是不同的,为了保证Golden Test
在不同的设备上运行时生成的图片一致,所以将字体都渲染成了矩形,但是这样我们就无法通过查看图片来验证UI显示是否符合预期了,而且在运行在Ci/Cd
机子的设备基本都是统一的。所以并不需要将此渲染成矩形。
这里我通过引入三方库golden_toolkit
来解决此问题。golden_toolkit
也能帮助开发者更加易于编写Golden Test
。它的优势这里不作过多赘述。
引入golden_toolkit
后,test文件夹下新建flutter_test_config.dart
。文件代码如下:
dart
import 'dart:async';
import 'dart:io';
import 'package:golden_toolkit/golden_toolkit.dart';
Future<void> testExecutable(FutureOr<void> Function() testMain) async {
return GoldenToolkit.runWithConfiguration(
() async {
await loadAppFonts();
await testMain();
},
config: GoldenToolkitConfiguration(
// Currently, goldens are not generated/validated in CI for this repo. We have settled on the goldens for this package
// being captured/validated by developers running on MacOSX. We may revisit this in the future if there is a reason to invest
// in more sophistication
skipGoldenAssertion: () => !Platform.isMacOS,
),
);
}
然后下载第三方字体文件进行导入,这是因为golden_toolkit
自带的字体只支持渲染英文。然后在pubspec.yaml
中的flutter 标签下添加如下字符串。
在实际项目中直接导入字体文件会使包体积增加一些无用文件。而字体暂时不能像dev_dependencies
一样添加只在开发中引用的库。github.com/flutter/flu...
这里我建议在项目中文件夹里再建一个flutter example
,在该example
里写Golden Test
。
这些操作后开始编写基于golden_toolkit
的Golden Test
。新建circle_button_test
。在test文件夹中
dart
import 'package:flutter_golden_test_example/circle_button.dart';
import 'package:golden_toolkit/golden_toolkit.dart';
void main() {
testGoldens('Circle button', (tester) async {
final builder = GoldenBuilder.grid(
columns: 3,
widthToHeightRatio: 1,
)
..addScenario(
'alarm',
const CircleButton(icon: 'assets/images/ic_alarm.svg', text: '时钟'),
)
..addScenario(
'notification',
const CircleButton(
icon: 'assets/images/ic_notification.svg', text: '通知'),
);
await tester.pumpWidgetBuilder(builder.build());
await screenMatchesGolden(tester, 'circle_button');
});
}
然后运行flutter test --update-goldens
就会生成如下文件。这就是基准图片。
然后我们模拟下对该UI在新增功能时出现的破坏性变更导致文本字体颜色错误。
此时运行flutter test
。则会报错。图中圈出来的信息则告知了当前UI代码输出的图和基准图的差异比例。并新增了failures文件夹,里面的文件分别表示的作用是:
文件后缀名 | 作用 |
---|---|
xx_isolatedDiff | 标记两者差异的图片 |
xx_maskedDiff | 标记两者差异的图片 |
xx_masterImage | 基准图片 |
xx_testImage | 被测试图片(当前UI代码生成的图片) |
其中isolatedDiff和maskedDiff的差异,直接看图。
circle_button_isolatedDiff.png
circle_button_maskedDiff.png
这些Diff
的图片会圈出UI差异的地方。
最后记得还需要将 failures
文件夹添加在 .gitignore
中
相关链接
源代码仓库: github.com/drown0315/f...