Flutter测试中如何正确校验MaterialStateProperty属性值?
- 实现了可通过参数指定
elevation属性的ElevatedButton组件,核心实现代码:
child: ElevatedButton( key: const Key('MyButton'), onPressed: () {}, child: Text('My Button'), style: ButtonStyle( elevation: MaterialStateProperty.all<double>(2.0), ), ), ...
- 尝试编写测试用例校验按钮的
elevation属性,最初编写的测试代码:
final button = tester .widget<ElevatedButton>(find.byKey(Key('NewSessionsElevatedButton'))); expect(button.style.elevation, MaterialStateProperty.all<double>(2.0));
- 运行测试时抛出失败异常,日志显示预期值和实际值的打印结果完全一致,但测试仍然判定不通过,错误日志如下:
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════ The following TestFailure object was thrown running a test: Expected: _MaterialStatePropertyAll<double>:<MaterialStateProperty.all(2.0)> Actual: _MaterialStatePropertyAll<double>:<MaterialStateProperty.all(2.0)>
- 查阅官方相关测试用例后未找到清晰的示例,需要明确
MaterialStateProperty类型属性的正确测试方式。
MaterialStateProperty.all()构造返回_MaterialStatePropertyAll私有类实例,该类未重写==操作符与hashCode getter,默认继承Object的相等判断逻辑为引用相等:即便两个实例包裹的属性值完全一致,只要不是同一个实例,直接做相等判断就会返回false,这就是日志打印内容完全一致但测试失败的核心原因。
另外测试代码存在笔误:组件定义时传入的key为MyButton,测试中查找的key为NewSessionsElevatedButton,运行时会先触发找不到组件的错误,需要先将两处key修正为一致。
通用的标准测试写法为:不直接比较MaterialStateProperty实例,而是调用实例的resolve()方法,传入待校验的组件状态集合,拿到解析后的实际属性值再做断言。这种写法不耦合属性实现逻辑,无论是固定值的MaterialStateProperty.all(),还是根据状态动态返回值的MaterialStateProperty.resolveWith()都可以正常校验。
校验默认常态下的属性值
传入空状态集合,即可拿到组件无交互(未按下、未禁用、未聚焦、未选中)时的属性值:
// 先修正key,和组件定义保持一致 final button = tester.widget<ElevatedButton>(find.byKey(const Key('MyButton'))); // 解析默认状态下的elevation值 final defaultElevation = button.style?.elevation?.resolve({}); expect(defaultElevation, 2.0);
校验特定交互状态下的属性值
如果需要校验按钮按下、禁用、聚焦等特定状态下的属性值,只需将对应状态传入resolve()的参数集合即可,例如校验按下状态的elevation:
final pressedElevation = button.style?.elevation?.resolve({MaterialState.pressed}); // 替换为对应状态下的预期elevation值做断言 expect(pressedElevation, 4.0);
如果需要明确校验属性的实现类型为固定值的MaterialStatePropertyAll,也可以通过类型断言后取内部value值判断,但这种写法耦合实现逻辑,不推荐使用:
final elevationProperty = button.style?.elevation; expect(elevationProperty, isA<MaterialStatePropertyAll<double>>()); final fixedElevation = (elevationProperty as MaterialStatePropertyAll<double>).value; expect(fixedElevation, 2.0);
内容的提问来源于stack exchange,提问作者Miguel de Sousa

