代码之家  ›  专栏  ›  技术社区  ›  Mary

如何测试initState()中存在异步调用的颤振应用程序?

  •  1
  • Mary  · 技术社区  · 7 年前

    我有一个StatefulWidget,在它的 initState() ,以构建小部件。当我手动运行这个程序时,小部件确实构建得很快。

    然而,在我的测试中,即使我使用 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 打印,但这只发生在最后一次打印时,在Flitter内置之前 (tearDownAll)

    在pump()和pumpAndSettle()中设置持续时间似乎不会改变任何事情。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Dan Field    7 年前

    考虑使用 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);
    
        2
  •  0
  •   Alex Rindone    6 年前

    我有一个未来的建设者在等待,它没有完成或抛出任何错误。futurebuilder有一个加载文件的未来,因此它应该能够这样做。应用程序工作正常,但测试不正常。

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