通过集成测试测量性能
性能移动应用用户来说相当重要,用户希望应用程序有流畅的滚动和优雅的动画,不愿看到卡顿和掉帧现象。我们如何确保我们的应用程序在各种设备上不会受到卡顿的影响?
以下两种方式可供选择:首先,我们可以在不同的设备对应用程序进行手动测试。这种方式适用于较小的应用程序,但随着应用程序扩展性的提升,它将变得更加繁琐。另外,我们可以运行集成测试,执行特定任务并记录性能时间轴。然后,我们可以检验结果,以确定是否需要对我们应用程序的特定部分进行改善。
在本文中,我们将学习如何在执行特定任务时编写记录性能时间轴的测试,并将结果的摘要保存到本地文件中。
步骤:
-
编写一个滚动列表的测试项目;
-
记录应用程序的性能;
-
将结果保存到磁盘;
-
运行测试;
-
检查结果。
1. 编写一个滚动列表的测试项目
#在这一小节,我们将记录当滚动列表条目时应用程序的性能。为了专注于性能分析,这一小节在组件测试中 Scrolling in integration tests(列表滚动集成测试) 的基础上进行。
请按照基础章节的指南新建一个应用程序,编写一个测试程序。最终,确保应用程序按预期运行。
2. 记录应用程序的性能
#然后,我们需要再应用程序的列表滚动的时候记录它的性能。使用 IntegrationTestWidgetsFlutterBinding
类中的 traceAction()
方法实现这项功能。
这种方式运行提供的方法,并将应用程序性能的详细信息记录在 Timeline
中。在这个示例中,我们提供一个方法,用以滚动列表的条目并确保指定条目是否被显示出来。当方法执行完成的时候,traceAction()
会返回一个 Timeline
。
当运行一个以上的 traceAction
的时候需要指定 reportKey
。默认情况下,所有的 Timelines
都会存在 timeline
里,在这个例子中,reportKey
被修改为了 scrolling_timeline
:
await binding.traceAction(
() async {
// Scroll until the item to be found appears.
await tester.scrollUntilVisible(
itemFinder,
500.0,
scrollable: listFinder,
);
},
reportKey: 'scrolling_timeline',
);
3. 将结果保存到磁盘
#我们已经获取了一个性能时间轴,我们需要一种方式来对它进行检验,
Timeline
对象提供所有已发生事件的相关详细信息,但它不提供快捷方式查看结果。
因此,我们可以将 Timeline
转换成 TimelineSummary
,
TimelineSummary
通过执行两个任务可以使我们更容易的检查结果:
-
将一个 json 文件写入磁盘,它包含了
Timeline
中包含的数据的摘要。此摘要包括掉帧数量,最慢构建时间等的信息。 -
它可以将完整的
Timeline
以 json 文件的形式存储在磁盘上,可以使用 Chrome 浏览器的追踪工具打开此文件。追踪工具在这里:chrome://tracing
。
为了捕获结果内容,需要在 test_driver
文件夹中新建一个 perf_driver.dart
文件,并加入如下代码:
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() {
return integrationDriver(
responseDataCallback: (data) async {
if (data != null) {
final timeline = driver.Timeline.fromJson(
data['scrolling_timeline'] as Map<String, dynamic>,
);
// Convert the Timeline into a TimelineSummary that's easier to
// read and understand.
final summary = driver.TimelineSummary.summarize(timeline);
// Then, write the entire timeline to disk in a json format.
// This file can be opened in the Chrome browser's tracing tools
// found by navigating to chrome://tracing.
// Optionally, save the summary to disk by setting includeSummary
// to true
await summary.writeTimelineToFile(
'scrolling_timeline',
pretty: true,
includeSummary: true,
);
}
},
);
}
你可以自定义 integrationDriver
函数的 responseDataCallback
方法,默认情况下,它会将结果写入 integration_response_data.json
文件,不过你也可以通过这个例子里的方法重写为生成摘要。
4. 运行测试
#在我们为了捕获一个性能 Timeline
配置了测试代码,并且将结果的摘要保存在了磁盘上,我们可以使用以下命令运行测试代码:
flutter drive \
--driver=test_driver/perf_driver.dart \
--target=integration_test/scrolling_test.dart \
--profile
--profile
命令行选项代表着应用将以 profile 模式 (性能模式) 运行,这种模式下运行的应用会比 debug 模式更接近最终用户的体验。
5. 检查结果
#在测试代码运行成功以后,在项目根目录下的 build
文件夹里包含以下两个文件:
-
scrolling_summary.timeline_summary.json
包含摘要。可以使用任何文本编辑器打开它并查看其中包含的信息。通过更高级的设置,我们可以在每次测试时保存摘要并创建一个结果图。 -
scrolling_timeline.timeline.json
包含完整的时间轴数据。使用 Chorme 浏览器的追踪工具打开这个文件。追踪工具在这里:chrome://tracing
。追踪工具提供了一个便捷的用户界面,用以检测时间轴数据并发现其中导致性能问题的源头。
摘要的示例
#{
"average_frame_build_time_millis": 4.2592592592592595,
"worst_frame_build_time_millis": 21.0,
"missed_frame_build_budget_count": 2,
"average_frame_rasterizer_time_millis": 5.518518518518518,
"worst_frame_rasterizer_time_millis": 51.0,
"missed_frame_rasterizer_budget_count": 10,
"frame_count": 54,
"frame_build_times": [
6874,
5019,
3638
],
"frame_rasterizer_times": [
51955,
8468,
3129
]
}
完整样例
#integration_test/scrolling_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:scrolling/main.dart';
void main() {
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Counter increments smoke test', (tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp(
items: List<String>.generate(10000, (i) => 'Item $i'),
));
final listFinder = find.byType(Scrollable);
final itemFinder = find.byKey(const ValueKey('item_50_text'));
await binding.traceAction(
() async {
// Scroll until the item to be found appears.
await tester.scrollUntilVisible(
itemFinder,
500.0,
scrollable: listFinder,
);
},
reportKey: 'scrolling_timeline',
);
});
}
test_driver/perf_driver.dart
import 'package:flutter_driver/flutter_driver.dart' as driver;
import 'package:integration_test/integration_test_driver.dart';
Future<void> main() {
return integrationDriver(
responseDataCallback: (data) async {
if (data != null) {
final timeline = driver.Timeline.fromJson(
data['scrolling_timeline'] as Map<String, dynamic>,
);
// Convert the Timeline into a TimelineSummary that's easier to
// read and understand.
final summary = driver.TimelineSummary.summarize(timeline);
// Then, write the entire timeline to disk in a json format.
// This file can be opened in the Chrome browser's tracing tools
// found by navigating to chrome://tracing.
// Optionally, save the summary to disk by setting includeSummary
// to true
await summary.writeTimelineToFile(
'scrolling_timeline',
pretty: true,
includeSummary: true,
);
}
},
);
}
除非另有说明,本文档之所提及适用于 Flutter 的最新稳定版本,本页面最后更新时间: 2024-05-20。 查看文档源码 或者 为本页面内容提出建议。