【问题标题】:How to wait for Future method inside widget testing?如何在小部件测试中等待 Future 方法?
【发布时间】:2019-11-21 08:43:16
【问题描述】:

我想测试我的小部件。在我的 HomePage 小部件中,有一个调用 API 的方法,然后它将在这个小部件中显示结果。这是主页小部件的代码

class HomePage extends StatefulWidget {
  WebScraper _webScraper = WebScraper();

  HomePage();

  HomePage.forTest(Client client) {
    _webScraper.client = client;
  }

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List<Post> posts = [];

  bool isPostLoaded = false;

  @override
  void initState() {
    super.initState();
    _onRefresh();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          Expanded(
            child: RefreshIndicator(
              child: isPostLoaded ? ListView.builder(
                key: Key('post-list'),
                itemCount: posts.length,
                itemBuilder: (context, index) {
                  return Card(
                    key: Key(posts[index].id.toString()),
                    child: Column(
                      children: <Widget>[
                        Text(posts[index].title),
                        Text(posts[index].content),
                        Row(
                          children: <Widget>[
                          // some code
                          ],
                        )
                      ],
                    ),
                  );
                },
              ) : CircularProgressIndicator(),
              onRefresh: _onRefresh),
          ),
        ],
      ),
    );
  }

  Future<void> _onRefresh() async {
    List<Post> postFromWebsite =
        await this.widget._webScraper.getPostsFromWebsite();
    if (postFromWebsite.length > 0) {
      setState(() {
        posts = postFromWebsite;
        isPostLoaded = true;
      });
    }
  }

这是我的测试代码

void main() {
  var homeHttpMock;
  setUp(() {
    MockClient client = MockClient((request) async {
      String html =
          await rootBundle.loadString('test_resources/test.html');
      return Response(html, 200);
    });

    homeHttpMock = MediaQuery(
      data: MediaQueryData(),
      child: MaterialApp(
        home: HomePage.forTest(client),
      ),
    );
  });

  testWidgets('Show post inside card in the list view',
      (WidgetTester tester) async {
    await tester.pumpWidget(homeHttpMock);
    await tester.pump();
    final listView = find.byKey(Key('post-list'));
    expect(listView, findsOneWidget);
  });

我尝试使用tester.runAsynctester.pump 和持续时间、tester.pumpAndSettle(这个将超时)和FakeAsync,但这些方法不适用于我的小部件测试,它将引导我的测试失败。

提前谢谢你

【问题讨论】:

    标签: testing flutter dart


    【解决方案1】:

    你为什么不直接使用await Future.delayed(Duration(seconds: 5));

    只需使用您的虚假帖子使用的时间...

    【讨论】:

    • 感谢您的建议,但我也尝试过,但失败了。我添加了tester.binding.addTime(Duration(minutes: 5),但由于超时仍然失败。
    • 感谢您的帮助,我刚刚找到了解决方案。我会把它贴在下面
    • 算了,测试确实通过了,但是如果我更改 ListView 的键,测试仍然通过。
    • @10101010 不,但我想我明白为什么刚才测试失败了。我将在下面写下我找到的解决方案。
    • 我们正在等待您的宝贵解决方案。@AlmanteraTAlFaruqi
    【解决方案2】:

    在使用@LgFranco 的建议重构我的测试代码并仔细阅读此article 后,我找到了解决方案。

    我把我的测试代码改成了这个

    testWidgets('Show post inside card in the list view',
        (WidgetTester tester) async {
      await tester.pumpWidget(homeHttpMock);
      await tester.pumpAndSettle(); // Wait for refresh indicator to stop spinning
      final listView = find.byKey(Key('post-list'));
      expect(listView, findsOneWidget);
    });
    

    我必须使用flutter run my_test_code.dart 命令运行它,因为如果我不这样做,它会引发pumpAndSettle timed out 错误。然后我意识到这不是小部件测试,因为根据我阅读的文章,我无法在小部件测试中测试任何真正的异步工作。

    如果有人找到解决此问题的其他方法,请提及我。谢谢。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-10
      • 1970-01-01
      • 1970-01-01
      • 2023-01-14
      • 1970-01-01
      • 2015-03-01
      • 2013-04-21
      • 2020-09-29
      相关资源
      最近更新 更多