为什么我的集成测试中的小部件查找器在我的测试成功登录到我的 flutter 应用程序后找不到小部件?
why can't the widget finder in my integration test find a widget after my test successfully signs into my flutter app?
我正在尝试编写一些集成测试,这些测试从登录尝试开始,然后继续将应用程序导航到某个页面。登录尝试实际上成功了,但之后我尝试查找任何小部件失败,因此我无法进一步导航。
登录页面后,应用程序会自动正确导航到应用程序中的下一页,但我的测试脚本无法在该页面上找到任何小部件,即使我可以在 android 中看到它们屏幕上的模拟器。
我的 app_test.dat 文件如下所示:
import ...
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('sign in : ', () {
testWidgets('try to SIGN IN and open the menu ',
(WidgetTester tester) async {
app.main();
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await tester.pumpAndSettle();
expect(find.text('SIGN IN', skipOffstage: false), findsWidgets);
expect(find.byKey(Key('loginPagePasswordField')), findsOneWidget);
expect(find.byKey(Key('loginPageEmailField')), findsOneWidget);
print('found fields');
await tester.enterText(
find.byKey(Key('loginPageEmailField')), 'myname@here.com');
await tester.enterText(
find.byKey(Key('loginPagePasswordField')), 'myname123zxc');
print('entered text');
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pump();
print('entered DONE');
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await tester.pumpAndSettle();
// Now try to find the menu icon button
var x = find.byTooltip('Open navigation menu');
expect(x, findsOneWidget); // this fails but is needed to navigate the app
print('find tab1 ');
// Now try to find the 'ASD' Tab
final tabFinder = find.text('ASD', skipOffstage: false);
expect(tabFinder, findsWidgets); // this also fails
});
});
}
还有我的f医生(我用的是fvm):
[✓] Flutter (Channel stable, 2.8.0, on macOS 12.1 21C52 darwin-arm, locale en-CA)
[✓] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 13.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] VS Code (version 1.63.0)
[✓] Connected device (2 available)
• No issues found!
在此特定情况下找不到小部件的可能原因有多种:
- 它不在屏幕上(完全或滚出屏幕)
- 此处或实际代码中的工具提示不正确。
- 您尝试查找的小部件不是
Tooltip
小部件。
- 泵送时间太短。
- 也许是一些模拟器特定的东西。
现在有哪些可能的修复方法。
如果小部件在屏幕上并且对您可见并不意味着它对测试驱动程序可见 - 根据我的经验,这是很常见的情况。您可以尝试使用 tester.ensureVisible
使其可见。或者实际滚动内容以确保它在 tester.fling
、tester.scrollUntilVisible
或 tester.dragUntilVisible
.
中可见
检查工具提示字符串。我建议您不要以这种方式使用 findByTooltip
- 您可能不知道设备的 excat 语言环境,如果应用程序启用了本地化 - 查找器将失败。如果您完全确定应用程序中不会有本地化 - 创建一个带有工具提示的静态字符串并在代码和测试中使用它 - 这样您将确保字符串是相同的。使用本地化 - 在实施和测试中使用 InheritedWidget
方法并通过 appLocalizations.of(context)
从上下文中检索字符串。但这里的实际提议是根本不使用 findByTooltip
。 findByKey
更可靠,因为它独立于上下文区域设置和手动输入错误 - 只需按照我之前的建议使用键 - 创建静态常量键并在代码和测试中使用相同的常量。
检查 Tooltip
的 message
字段是否已填满,是否与您尝试查找的字段相同。
多抽一点 - 也许会有帮助。还尝试使用持续时间较长的 pump
,然后直接一个接一个地使用默认持续时间的 pumpAndSettle
- 有时它会有所帮助。
尝试在真实设备上运行测试。
您问题的一般答案是,如果一切都正确编码并且屏幕上有这样的小部件,finder 就会找到小部件。但我明白为什么它在某种程度上是有问题的——我已经编写了数千行 flutter 集成测试并且我已经看到了各种人为错误(包括我的错误)、奇怪的 driver/tester/finder 行为和 device/os/framewok 特定案例。
似乎诀窍在于,当集成测试为 运行 时,AppBar 的默认“前导”小部件或默认前导小部件的默认工具提示不存在。当应用程序在模拟器中处于 运行 调试模式时,它就在那里 - 它可以通过 MaterialLocalizations.of(context).openAppDrawerTooltip
上的调试监视找到。当我 运行 对测试文件进行调试时,该手表没有找到工具提示 - 然后在这种情况下似乎又没有手表工作。
修复方法是手动将“前导”小部件添加到 AppBar 中,如下所示:
appBar: AppBar(
title: "my title",
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: Icon(Icons.menu),
onPressed: () {
Scaffold.of(context).openDrawer();
},
tooltip: 'Open navigation menu',
);
},
),
...
现在,进入下一个问题 - 为什么组中的下一个测试找不到任何小部件?
我正在尝试编写一些集成测试,这些测试从登录尝试开始,然后继续将应用程序导航到某个页面。登录尝试实际上成功了,但之后我尝试查找任何小部件失败,因此我无法进一步导航。
登录页面后,应用程序会自动正确导航到应用程序中的下一页,但我的测试脚本无法在该页面上找到任何小部件,即使我可以在 android 中看到它们屏幕上的模拟器。
我的 app_test.dat 文件如下所示:
import ...
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('sign in : ', () {
testWidgets('try to SIGN IN and open the menu ',
(WidgetTester tester) async {
app.main();
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await tester.pumpAndSettle();
expect(find.text('SIGN IN', skipOffstage: false), findsWidgets);
expect(find.byKey(Key('loginPagePasswordField')), findsOneWidget);
expect(find.byKey(Key('loginPageEmailField')), findsOneWidget);
print('found fields');
await tester.enterText(
find.byKey(Key('loginPageEmailField')), 'myname@here.com');
await tester.enterText(
find.byKey(Key('loginPagePasswordField')), 'myname123zxc');
print('entered text');
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pump();
print('entered DONE');
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await tester.pumpAndSettle();
// Now try to find the menu icon button
var x = find.byTooltip('Open navigation menu');
expect(x, findsOneWidget); // this fails but is needed to navigate the app
print('find tab1 ');
// Now try to find the 'ASD' Tab
final tabFinder = find.text('ASD', skipOffstage: false);
expect(tabFinder, findsWidgets); // this also fails
});
});
}
还有我的f医生(我用的是fvm):
[✓] Flutter (Channel stable, 2.8.0, on macOS 12.1 21C52 darwin-arm, locale en-CA)
[✓] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 13.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] VS Code (version 1.63.0)
[✓] Connected device (2 available)
• No issues found!
在此特定情况下找不到小部件的可能原因有多种:
- 它不在屏幕上(完全或滚出屏幕)
- 此处或实际代码中的工具提示不正确。
- 您尝试查找的小部件不是
Tooltip
小部件。 - 泵送时间太短。
- 也许是一些模拟器特定的东西。
现在有哪些可能的修复方法。
如果小部件在屏幕上并且对您可见并不意味着它对测试驱动程序可见 - 根据我的经验,这是很常见的情况。您可以尝试使用
中可见tester.ensureVisible
使其可见。或者实际滚动内容以确保它在tester.fling
、tester.scrollUntilVisible
或tester.dragUntilVisible
.检查工具提示字符串。我建议您不要以这种方式使用
findByTooltip
- 您可能不知道设备的 excat 语言环境,如果应用程序启用了本地化 - 查找器将失败。如果您完全确定应用程序中不会有本地化 - 创建一个带有工具提示的静态字符串并在代码和测试中使用它 - 这样您将确保字符串是相同的。使用本地化 - 在实施和测试中使用InheritedWidget
方法并通过appLocalizations.of(context)
从上下文中检索字符串。但这里的实际提议是根本不使用findByTooltip
。findByKey
更可靠,因为它独立于上下文区域设置和手动输入错误 - 只需按照我之前的建议使用键 - 创建静态常量键并在代码和测试中使用相同的常量。检查
Tooltip
的message
字段是否已填满,是否与您尝试查找的字段相同。多抽一点 - 也许会有帮助。还尝试使用持续时间较长的
pump
,然后直接一个接一个地使用默认持续时间的pumpAndSettle
- 有时它会有所帮助。尝试在真实设备上运行测试。
您问题的一般答案是,如果一切都正确编码并且屏幕上有这样的小部件,finder 就会找到小部件。但我明白为什么它在某种程度上是有问题的——我已经编写了数千行 flutter 集成测试并且我已经看到了各种人为错误(包括我的错误)、奇怪的 driver/tester/finder 行为和 device/os/framewok 特定案例。
似乎诀窍在于,当集成测试为 运行 时,AppBar 的默认“前导”小部件或默认前导小部件的默认工具提示不存在。当应用程序在模拟器中处于 运行 调试模式时,它就在那里 - 它可以通过 MaterialLocalizations.of(context).openAppDrawerTooltip
上的调试监视找到。当我 运行 对测试文件进行调试时,该手表没有找到工具提示 - 然后在这种情况下似乎又没有手表工作。
修复方法是手动将“前导”小部件添加到 AppBar 中,如下所示:
appBar: AppBar(
title: "my title",
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: Icon(Icons.menu),
onPressed: () {
Scaffold.of(context).openDrawer();
},
tooltip: 'Open navigation menu',
);
},
),
...
现在,进入下一个问题 - 为什么组中的下一个测试找不到任何小部件?