选择另一个项目时,Flutter 小部件测试不会触发 DropdownButton.onChanged
Flutter widget test does not trigger DropdownButton.onChanged when selecting another item
我正在编写一个 Flutter 网络应用程序,并将一些小部件测试添加到我的代码库中。我很难让 flutter_test 按预期工作。我面临的当前问题是尝试 select DropdownButton 中的值。
下面是重现问题的完整小部件测试代码:
void main() {
group('description', () {
testWidgets('description', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: Card(
child: Column(
children: [
Expanded(
child: DropdownButton(
key: Key('LEVEL'),
items: [
DropdownMenuItem<String>(
key: Key('Greater'),
value: 'Greater',
child: Text('Greater'),
),
DropdownMenuItem<String>(
key: Key('Lesser'),
value: 'Lesser',
child: Text('Lesser'),
),
],
onChanged: (value) {
print('$value');
},
value: 'Lesser',
),
)
],
),
),
));
expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
equals('Lesser'));
await tester.tap(find.byKey(Key('LEVEL')));
await tester.tap(find.byKey(Key('Greater')));
await tester.pumpAndSettle();
expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
equals('Greater'));
});
});
}
此测试未达到最终预期 -- expect(widget.value, equals('Greater'));
永远不会调用 onChanged 回调,正如我在调试器中看到的那样,或者在输出中查找我的打印语句。
测试 DropdownButton 行为的魔法是什么?
测试时,在任何用户交互相关代码之后添加 tester.pump()
调用很重要。
下拉按钮的测试与通常的小部件略有不同。对于所有情况,最好参考 here,这是对 dropdownbutton 的实际测试。
测试时的一些提示。
- DropdownButton 由按钮的 'IndexedStack' 和菜单项列表的普通堆栈组成。
- 您为
DropDownMenuItem
分配的密钥和文本以某种方式提供给上述堆栈中的两个小部件。
- 点击时选择返回的小部件列表中的最后一个元素。
- 此外,下拉按钮需要一些时间来制作动画,因此我们按照来自 flutter 的参考测试中的建议调用
tester.pump
两次。
DropdownButton
的value
属性不会自动改变。它必须使用 setState
进行设置。因此,您的最后一行断言是错误的,除非您将测试包装在 here. 之类的 StatefulBuilder
中,否则它将不起作用
有关如何使用 DropDownButton
的更多详细信息,请查看此 post
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('description', () {
testWidgets('description', (WidgetTester tester) async {
String changedValue = 'Lesser';
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Center(
child: RepaintBoundary(
child: Card(
child: Column(
children: [
Expanded(
child: DropdownButton(
key: Key('LEVEL'),
items: [
DropdownMenuItem<String>(
key: ValueKey<String>('Greater'),
value: 'Greater',
child: Text('Greater'),
),
DropdownMenuItem<String>(
key: Key('Lesser'),
value: 'Lesser',
child: Text('Lesser'),
),
],
onChanged: (value) {
print('$value');
changedValue = value;
},
value: 'Lesser',
),
)
],
),
),
),
),
),
));
expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
equals('Lesser'));
// Here before the menu is open we have one widget with text 'Lesser'
await tester.tap(find.text('Lesser'));
// Calling pump twice once comple the the action and
// again to finish the animation of closing the menu.
await tester.pump();
await tester.pump(Duration(seconds: 1));
// after opening the menu we have two widgets with text 'Greater'
// one in index stack of the dropdown button and one in the menu .
// apparently the last one is from the menu.
await tester.tap(find.text('Greater').last);
await tester.pump();
await tester.pump(Duration(seconds: 1));
/// We directly verify the value updated in the onchaged function.
expect(changedValue, 'Greater');
/// The follwing expectation is wrong because you haven't updated the value
/// of dropdown button.
// expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
// equals('Greater'));
});
});
}
我正在编写一个 Flutter 网络应用程序,并将一些小部件测试添加到我的代码库中。我很难让 flutter_test 按预期工作。我面临的当前问题是尝试 select DropdownButton 中的值。
下面是重现问题的完整小部件测试代码:
void main() {
group('description', () {
testWidgets('description', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: Card(
child: Column(
children: [
Expanded(
child: DropdownButton(
key: Key('LEVEL'),
items: [
DropdownMenuItem<String>(
key: Key('Greater'),
value: 'Greater',
child: Text('Greater'),
),
DropdownMenuItem<String>(
key: Key('Lesser'),
value: 'Lesser',
child: Text('Lesser'),
),
],
onChanged: (value) {
print('$value');
},
value: 'Lesser',
),
)
],
),
),
));
expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
equals('Lesser'));
await tester.tap(find.byKey(Key('LEVEL')));
await tester.tap(find.byKey(Key('Greater')));
await tester.pumpAndSettle();
expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
equals('Greater'));
});
});
}
此测试未达到最终预期 -- expect(widget.value, equals('Greater'));
永远不会调用 onChanged 回调,正如我在调试器中看到的那样,或者在输出中查找我的打印语句。
测试 DropdownButton 行为的魔法是什么?
测试时,在任何用户交互相关代码之后添加 tester.pump()
调用很重要。
下拉按钮的测试与通常的小部件略有不同。对于所有情况,最好参考 here,这是对 dropdownbutton 的实际测试。
测试时的一些提示。
- DropdownButton 由按钮的 'IndexedStack' 和菜单项列表的普通堆栈组成。
- 您为
DropDownMenuItem
分配的密钥和文本以某种方式提供给上述堆栈中的两个小部件。 - 点击时选择返回的小部件列表中的最后一个元素。
- 此外,下拉按钮需要一些时间来制作动画,因此我们按照来自 flutter 的参考测试中的建议调用
tester.pump
两次。 DropdownButton
的value
属性不会自动改变。它必须使用setState
进行设置。因此,您的最后一行断言是错误的,除非您将测试包装在 here. 之类的
StatefulBuilder
中,否则它将不起作用
有关如何使用 DropDownButton
的更多详细信息,请查看此 post
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('description', () {
testWidgets('description', (WidgetTester tester) async {
String changedValue = 'Lesser';
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Center(
child: RepaintBoundary(
child: Card(
child: Column(
children: [
Expanded(
child: DropdownButton(
key: Key('LEVEL'),
items: [
DropdownMenuItem<String>(
key: ValueKey<String>('Greater'),
value: 'Greater',
child: Text('Greater'),
),
DropdownMenuItem<String>(
key: Key('Lesser'),
value: 'Lesser',
child: Text('Lesser'),
),
],
onChanged: (value) {
print('$value');
changedValue = value;
},
value: 'Lesser',
),
)
],
),
),
),
),
),
));
expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
equals('Lesser'));
// Here before the menu is open we have one widget with text 'Lesser'
await tester.tap(find.text('Lesser'));
// Calling pump twice once comple the the action and
// again to finish the animation of closing the menu.
await tester.pump();
await tester.pump(Duration(seconds: 1));
// after opening the menu we have two widgets with text 'Greater'
// one in index stack of the dropdown button and one in the menu .
// apparently the last one is from the menu.
await tester.tap(find.text('Greater').last);
await tester.pump();
await tester.pump(Duration(seconds: 1));
/// We directly verify the value updated in the onchaged function.
expect(changedValue, 'Greater');
/// The follwing expectation is wrong because you haven't updated the value
/// of dropdown button.
// expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
// equals('Greater'));
});
});
}