首页 > 解决方案 > flutter_test 是否支持测试“叶子”小部件?

问题描述

假设我创建了一个简单的小部件,例如:

class RightArrowButton extends StatelessWidget {
  const RightArrowButton({VoidCallback onPressed})
      : this._onPressed = onPressed;

  final VoidCallback _onPressed;

  @override
  Widget build(BuildContext context) {
    return IconButton(
      visualDensity: VisualDensity.compact,
      onPressed: _onPressed,
      icon: _buildIcon(iconData()),
    );
  }

  /// Overrride to set a different icon.
  IconData iconData() => Icons.play_arrow;

  Widget _buildIcon(IconData icon) => Icon(icon, color: Colors.blue);
}

进一步假设我希望对这个小部件进行单元测试。我知道,这是一个非常简单的小部件,但我可能首先尝试使用 TDD 来编写小部件。无论如何,我可以将这个概念应用到更复杂的小部件上。

在这种情况下,测试将非常简单:构造小部件,向其传递一个 onPressed 函数,可以检查其副作用以验证当有人点击小部件时实际调用了 onPressed 方法。

示例测试代码:

void main() {
  testWidgets('RightArrowButton', (WidgetTester tester) async {
    int counter = 0;

    await tester.pumpWidget(RightArrowButton(
      onPressed: () => counter++,
    ));
    
    expect(0, equals(counter));

    var button = find.byType(IconButton);
    await tester.tap(button);
    
    expect(1, equals(counter));
  });
}

但是,当我这样做时,我收到以下错误:

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building IconButton(Icon, padding: EdgeInsets.all(8.0), dirty):
No Material widget found.
IconButton widgets require a Material widget ancestor.

阅读此 SO 问题后,我了解错误:

未找到材质小部件

那么——有没有办法以我想要的方式对小部件进行单元测试?或者我是否被迫测试整个小部件组件以获得有效的 Material 小部件祖先(这更像是一个小型集成测试)?

标签: flutterflutter-test

解决方案


我找到了一个可行的解决方案。Flutter 专家,以下方法是实现我隔离测试单个小部件目标的唯一或最佳方法吗?

void main() {
  testWidgets('arrow test', (WidgetTester tester) async {
    int counter = 0;

    // must include Card to get Material; 
    // must include MaterialApp to get Directionality
    await tester.pumpWidget(MaterialApp(
      home: Card(
        child: RightArrowButton(
          onPressed: () => counter++,
        ),
      ),
    ));

    await tester.tap(find.byType(RightArrowButton));

    expect(1, equals(counter));
  });
}

推荐阅读