如何在 initState() 中有异步调用的地方测试 Flutter 应用程序?

Mar*_*ary 6 testing asynchronous dart flutter

我有一个 StatefulWidget,它在它的 中执行异步调用initState()来构建一个 Widget。当我手动运行它时,小部件确实可以快速构建。

但是,在我的测试中,即使我使用await tester.pump()await tester.pumpAndSettle(),小部件似乎也没有构建,直到测试运行之后。

小部件代码:

Widget _coolWidget;

@override
void initState() {
  super.initState();
  _coolWidget = Container(); // If I set this to OverflowBox() my test passes
  _buildWidgetFromCanvas();
}

Future<void> _buildWidgetFromCanvas() {
  final ui.PictureRecorder recorder = ui.PictureRecorder();
  final ui.Canvas canvas = ui.Canvas(recorder);
  // ... more canvas drawing code ...
  final img = ... // Image.memory() I build from the canvas
  if (!mounted) {
    print('no longer mounted');
    return;
  }

  setState(() {
    print(img);
    _coolWidget = OverflowBox(
      child: img,
    );
    print(_coolWidget);
  });
}
Run Code Online (Sandbox Code Playgroud)

测试代码:

void main() {
  testWidgets('''OverflowBox shows up.''', (WidgetTester tester) async {
    await _setUp(tester); // Just instantiates my widget in an app
    await tester.pumpAndSettle();
    expect(find.byType(OverflowBox).evaluate().length, 1);
  });
}
Run Code Online (Sandbox Code Playgroud)

我运行测试时的输出结果为:

failed: Error caught by Flutter test framework, thrown running a test.
Expected: <1>
Actual: <0>
Run Code Online (Sandbox Code Playgroud)

但是如果我设置_coolWidget = OverflowBox();initState(),测试就通过了。

我还有其他测试在此之后运行。完成这些后,我看到打印记录print(img);print(_coolWidget);从上面记录,并且它正确记录了绘制的图像。

我也得到了no longer mounted打印,但这只发生在 Flutter 内置(tearDownAll).

在 pump() 和 pumpAndSettle() 中设置持续时间似乎没有任何改变。

我可能遗漏了一些明显的东西。

Dan*_*eld 1

FutureBuilder如果您的build方法依赖于异步工作, 请考虑使用 a 。


Future<Image> _buildWidgetFromCanvas() {
  final ui.PictureRecorder recorder = ui.PictureRecorder();
  final ui.Canvas canvas = ui.Canvas(recorder);
  // ... more canvas drawing code ...
  if (!mounted) {
    return null
  }
  final img = ... // Image.memory() I build from the canvas
  return img;
}

FutureBuilder<Image>(
  future: _buildWidgetFromCanvas, // a previously-obtained Future<Image> or null
  builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
    switch (snapshot.connectionState) {
      case ConnectionState.none:
      case ConnectionState.active:
      case ConnectionState.waiting:
        return SizedBox(height: <height>, width: <width>);
      case ConnectionState.done:
        return OverflowBox(child: snapshot.data);
    }
    return null; // unreachable
  },
)
Run Code Online (Sandbox Code Playgroud)

您还可以像这样更新测试代码:

  expect(find.byType(OverflowBox), findsOneWidget);
Run Code Online (Sandbox Code Playgroud)