如何测试自定义SearchDelegate?

时间:2019-08-15 14:51:42

标签: flutter dart flutter-test

我正在测试我的自定义SearchDelegate。测试示例将检查开始提供建议的字符数之后。

我写了两个示例测试,它们以某种方式相互影响。它们都是相同的,但是当我一起运行它们时,稍后出现在代码中的测试始终会失败。

在调试过程中,我发现FutureBuilder方法中的buildSuggestions不会等待searchEngine.search(query)的将来完成,而只会在第二次测试中发生。

点击搜索图标后,我已经尝试过在内部添加test.runAsync的{​​{1}}。另外,我简化了案例以使其更具可读性。

您可以在此处找到完整的代码:https://github.com/pmiara/search-delegate-test-fail 或在下面查看。

应用代码:

Future.delayed

测试文件:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class Entity {
  final String value;

  Entity.fromJson(Map<String, dynamic> json) : value = json['value'];
}

class MySearchDelegate extends SearchDelegate {
  final MySearchEngine searchEngine;

  MySearchDelegate({@required this.searchEngine});

  @override
  List<Widget> buildActions(BuildContext context) {
    return [];
  }

  @override
  Widget buildLeading(BuildContext context) {
    return IconButton(
      icon: Icon(Icons.arrow_back),
      onPressed: () {
        close(context, null);
      },
    );
  }

  @override
  Widget buildResults(BuildContext context) {
    return FutureBuilder<List<Entity>>(
      future: searchEngine.search(query),
      builder: (BuildContext context, AsyncSnapshot<List<Entity>> snapshot) {
        if (snapshot.connectionState == ConnectionState.done &&
            snapshot.hasData) {
          final entities = snapshot.data;
          return ListView.builder(
            itemCount: entities.length,
            itemBuilder: (context, index) => ListTile(
              title: Text(entities[index].value),
              onTap: () => close(context, entities[index]),
            ),
          );
        } else {
          return Column();
        }
      },
    );
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    return FutureBuilder<List<Entity>>(
      future: searchEngine.search(query),
      builder: (BuildContext context, AsyncSnapshot<List<Entity>> snapshot) {
        if (snapshot.connectionState == ConnectionState.done &&
            snapshot.hasData) {
          final entities = snapshot.data;
          return ListView.builder(
            itemCount: entities.length,
            itemBuilder: (context, index) => ListTile(
              title: Text(entities[index].value),
              onTap: () {
                query = entities[index].value;
                showResults(context);
              },
            ),
          );
        } else {
          return Column();
        }
      },
    );
  }
}

class MySearchEngine {
  Future<List<Entity>> search(String query) async {
    final jsonEntities =
        await rootBundle.loadString('test_resources/entities.json');
    final entities = jsonDecode(jsonEntities)
        .map<Entity>((json) => Entity.fromJson(json))
        .toList();
    return entities;
  }
}

class TestHomePage extends StatelessWidget {
  final MySearchDelegate delegate;

  const TestHomePage({@required this.delegate});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Builder(
        builder: (BuildContext context) {
          return Scaffold(
            body: Center(
              child: IconButton(
                icon: Icon(Icons.search),
                onPressed: () async {
                  showSearch(
                    context: context,
                    delegate: delegate,
                  );
                },
              ),
            ),
          );
        },
      ),
    );
  }
}

/// Run to see what tests should "see"
void main() => runApp(
      TestHomePage(
        delegate: MySearchDelegate(
          searchEngine: MySearchEngine(),
        ),
      ),
    );

pubsec.yaml:

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:search_delegate_test/search_delegate_problem.dart';

void main() {
  testWidgets('First test', (WidgetTester tester) async {
    final delegate = MySearchDelegate(
      searchEngine: MySearchEngine(),
    );
    await tester.pumpWidget(
      TestHomePage(
        delegate: delegate,
      ),
    );
    await tester.tap(find.byIcon(Icons.search));
    await tester.pumpAndSettle();
    await tester.enterText(find.byType(TextField), 'query');
    await tester.pumpAndSettle();

    expect(find.byType(ListTile), findsNWidgets(3));
  });

  testWidgets('Second test', (WidgetTester tester) async {
    final delegate = MySearchDelegate(
      searchEngine: MySearchEngine(),
    );
    await tester.pumpWidget(
      TestHomePage(
        delegate: delegate,
      ),
    );
    await tester.tap(find.byIcon(Icons.search));
    await tester.pumpAndSettle();
    await tester.enterText(find.byType(TextField), 'query');
    await tester.pumpAndSettle();

    expect(find.byType(ListTile), findsNWidgets(3));
  });
}

test_resources / entities.json:

name: search_delegate_test
description: A new Flutter application.

version: 1.0.0+1

environment:
  sdk: ">=2.2.2 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter
  test: any

flutter:
  assets:
    - test_resources/

  uses-material-design: true

[ { "value": "abc" }, { "value": "abc123" }, { "value": "123def" } ] 的结果(我正在使用Android Studio)

flutter doctor

我得到的错误:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.7.8+hotfix.4, on Linux, locale pl_PL.UTF-8)

[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Android Studio (version 3.4)
[!] IntelliJ IDEA Ultimate Edition (version 2019.1)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
[!] IntelliJ IDEA Community Edition (version 2019.1)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
[✓] Connected device (1 available)

! Doctor found issues in 2 categories.

0 个答案:

没有答案