unit-testing - 单元测试 -> 无法在此 ChangeNotifierProvider<Counter> 小部件上方找到正确的 Provider<Counter>

标签 unit-testing flutter flutter-test

我想在我的项目中为 Provider ( ChangeNotifierProvider ) 创建一个单元测试,我的单元测试、小部件测试和集成测试成功通过 ✔️,所以现在我尝试(努力尝试🥵...)创建一个单元测试以提供者。我能够检查上下文,但是在检查提供程序的初始值(必须为 0)时,我收到此异常❌:

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following ProviderNotFoundError was thrown running a test:
Error: Could not find the correct Provider<Counter> above this ChangeNotifierProvider<Counter>
Widget

To fix, please:

  * Ensure the Provider<Counter> is an ancestor to this ChangeNotifierProvider<Counter> Widget
  * Provide types to Provider<Counter>
  * Provide types to Consumer<Counter>
  * Provide types to Provider.of<Counter>()
  * Always use package imports. Ex: `import 'package:my_app/my_code.dart';
  * Ensure the correct `context` is being used.

If none of these solutions work, please file a bug at:
https://github.com/rrousselGit/provider/issues

When the exception was thrown, this was the stack:
#0      Provider.of (package:provider/src/provider.dart:264:7)
#1      main.<anonymous closure>.<anonymous closure> (file:///home/chinnonsantos/FlutterProjects/full_testing_flutter/test/unit/provider_test.dart:33:23)
<asynchronous suspension>
#2      testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:119:25)
<asynchronous suspension>
#3      TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:648:19)
<asynchronous suspension>
#6      TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:631:14)
#7      AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1016:24)
#13     AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1013:15)
#14     testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:116:22)
#15     Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:168:27)
<asynchronous suspension>
#16     Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:250:15)
<asynchronous suspension>
#21     Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:247:5)
#22     Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:166:33)
#27     Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:165:13)
<asynchronous suspension>
#28     Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:400:25)
<asynchronous suspension>
#42     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:382:19)
#43     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:416:5)
#44     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:172:12)
(elided 28 frames from class _FakeAsync, package dart:async, package dart:async-patch, and package stack_trace)

The test description was:
  Update when the value changes
════════════════════════════════════════════════════════════════════════════════════════════════════
00:03 +0 -1: [Provider] Update when the value changes [E]                                                               
  Test failed. See exception logs above.
  The test description was: Update when the value changes

00:03 +0 -1: Some tests failed.                                                                                         
Collecting coverage information...

按照我的代码:
- pubspec.yaml :
...
dependencies:
  flutter:
    sdk: flutter
  test: ^1.6.3
  provider: ^3.2.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_driver:
    sdk: flutter
  pedantic: ^1.8.0+1
...
  • lib/main.dart :

  • import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import 'package:full_testing_flutter/counter.dart';
    
    void main() {
      runApp(
        ChangeNotifierProvider(
          create: (context) => Counter(),
          child: MyApp(),
        ),
      );
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatelessWidget {
      final String title;
    
      MyHomePage({this.title});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'You have pushed the button this many times:',
                ),
                Consumer<Counter>(
                  builder: (context, counter, child) => Text(
                    '${counter.value}',
                    key: Key('counter'),
                    style: Theme.of(context).textTheme.display1,
                  ),
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            key: Key('increment'),
            onPressed: () =>
                Provider.of<Counter>(context, listen: false).increment(),
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
        );
      }
    }
    
  • lib/counter.dart :

  • import 'package:flutter/foundation.dart';
    
    class Counter with ChangeNotifier {
      int value = 0;
    
      void increment() {
        value++;
        // print('Value++: $value');
        notifyListeners();
      }
    
      void decrement() {
        value--;
        // print('Value--: $value');
        notifyListeners();
      }
    }
    
  • test/unit/provider_test.dart :

  • import 'package:flutter/material.dart';
    import 'package:flutter_test/flutter_test.dart';
    import 'package:provider/provider.dart';
    
    import 'package:full_testing_flutter/main.dart';
    import 'package:full_testing_flutter/counter.dart';
    
    void main() async {
      Counter _counterModel;
    
      setUp(() {
        _counterModel = Counter();
      });
    
      group('[Provider]', () {
        testWidgets('Update when the value changes', (tester) async {
          final _providerKey = GlobalKey();
          BuildContext context;
    
          await tester.pumpWidget(ChangeNotifierProvider<Counter>(
            key: _providerKey,
            create: (c) {
              context = c;
              return Counter();
            },
            child: MyApp(),
          ));
    
          // Check the context test...
          expect(context, equals(_providerKey.currentContext));
    
          // Check the initial value provider 0...
          expect(Provider.of<Counter>(_providerKey.currentContext).value, 0);
    
          // // Increment value...
          // Provider.of<Counter>(_providerKey.currentContext).increment();
    
          // // Delay the pump...
          // await Future.microtask(tester.pump);
    
          // // Check if incremented value is the same as received...
          // expect(
          //   Consumer<Counter>(
          //     builder: (context, counter, child) => Text('${counter.value}'),
          //   ),
          //   _counterModel.value,
          // );
    
          // // Decrement value...
          // Provider.of<Counter>(context, listen: false).decrement();
    
          // // Delay the pump...
          // await Future.microtask(tester.pump);
    
          // // Check if decremented value is the same as received...
          // expect(
          //   Provider.of<Counter>(_childKey.currentContext).value,
          //   _counterModel.value,
          // );
        });
      });
    }
    
  • test/unit/counter_test.dart , test/widget/widget_test.darttest_driver/app_test.dart :

    It's not important right now, but if you want to see it, it's available in the full_testing_flutter (public project) repository


  • 我可以做什么来测试提供者(隔离)?我的代码中的错误在哪里?

    我从 Dart/Flutter 开始,尤其是 Provider 包,有人可以帮助我吗? 😥

    注意:我的应用程序运行良好,只有我对提供者的单元测试(我现在正在实现的)不起作用!!!

    谢谢

    最佳答案

    出现此问题是因为您使用的是 BuildContext您要获取的提供商的电话号码Provider.of :

    Provider<T>(
      key: myKey,
      ...
    )
    
    
    Provider.of<T>(myKey.currentContext);
    

    这是不可能的,只有该供应商的后代才能拨打Provider.of .

    考虑将您的测试更改为以下内容:

    testWidget('Provider.of', (tester) async {
      await tester.pumpWidget(
        Provider(
          create: (_) => 42,
          child: Container(),
        ),
      );
    
      final context = tester.element(find.byType(Container));
    
      expect(Provider.of<int>(context), equals(42));
    });
    

    关于unit-testing - 单元测试 -> 无法在此 ChangeNotifierProvider<Counter> 小部件上方找到正确的 Provider<Counter>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59148597/

    相关文章:

    java - 关于单元测试和日期的首选方法是什么?

    C# 单元测试 : Testing a method that uses MapPath

    c - 如何捕捉对 exit() 的调用(用于单元测试)

    firebase - 如何通过 Flutter 在 Firestore 中添加 Geopoint、时间戳和对文档的引用

    python - Pytest cov 不生成任何报告

    tabs - Flutter tabview刷新问题

    flutter - 如何将数据从方法_callLogs传递到正文并进行打印?

    flutter - 通过putifAbsent方法添加新项目后,我的 map 没有更新

    flutter - 在 Flutter 测试中从文件中读取资源

    flutter 测试 : How to only run one group or test