如何在小部件测试中等待Future方法?

时间:2019-07-11 15:14:19

标签: testing flutter dart

我想测试我的小部件。在我的Homepage小部件中,有一种方法可以调用API,然后它将在此小部件内显示结果。这是Homepage小部件的代码

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使用,但是这些方法不适用于我小部件测试,它将导致我的测试失败。

提前谢谢

2 个答案:

答案 0 :(得分:0)

您为什么不只使用await Future.delayed(Duration(seconds: 5));

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

答案 1 :(得分:0)

在使用@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错误。然后我意识到这不是小部件测试,因为根据我阅读的文章,我无法在小部件测试中测试任何真正的异步工作。

如果有人找到了解决此问题的另一种方法,请提及我。谢谢。