如何在initState()中存在异步调用的情况下测试Flutter应用?

时间:2018-11-28 03:02:49

标签: asynchronous testing 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);
  });
}

测试代码:

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);
  });
}

我在以下位置运行测试结果时的输出:

failed: Error caught by Flutter test framework, thrown running a test.
Expected: <1>
Actual: <0>

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

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

我也得到了no longer mounted印刷品,但这只是在Flutter内置(tearDownAll)之前的最后印刷品中发生的。

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

我可能缺少明显的东西。

2 个答案:

答案 0 :(得分:1)

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


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
  },
)

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

  expect(find.byType(OverflowBox), findsOneWidget);

答案 1 :(得分:0)

我有一个将来的构建器,它处于等待状态,并且没有完成或引发任何错误。 futurebuilder具有一个会加载文件的future,因此它应该能够执行该操作。该应用程序可以正常运行,但测试不能正常运行。

    // Create the widget by telling the tester to build it.
    await tester.pumpWidget(
        MaterialApp(home: DisplayPictureScreen(key: _globalKey, imagePath: 'test.png', onUpload: upload))
    );
    // Create the Finders.
    final safeAreaFinder = find.byKey(_globalKey);
    // expect we have one positioned widget
    expect(safeAreaFinder, findsOneWidget);
    await tester.pump();
    expect(find.byType(CircularProgressIndicator), findsOneWidget);
    // test code here
    await tester.pump(const Duration(seconds: 20));
    expect(find.byType(Expanded), findsOneWidget);
  });
}```