单元测试 -> 在此 ChangeNotifierProvider<Counter> 小部件上方找不到正确的 Provider<Counter>
Posted
技术标签:
【中文标题】单元测试 -> 在此 ChangeNotifierProvider<Counter> 小部件上方找不到正确的 Provider<Counter>【英文标题】:Unit Test -> Could not find the correct Provider<Counter> above this ChangeNotifierProvider<Counter> Widget 【发布时间】:2020-03-27 15:17:33 【问题描述】:我想在我的项目中为 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.dart
和 test_driver/app_test.dart
:
现在不重要,但如果您想查看它,可以在 full_testing_flutter (public project) 存储库中找到它
我可以做些什么来测试提供者(隔离)?我的代码中的错误在哪里?
我从 Dart/Flutter 开始,尤其是 Provider 包,有人可以帮助我吗? ????
注意:我的应用程序运行良好,只有我对提供者的单元测试(我现在正在实施的)不起作用!!!
谢谢
【问题讨论】:
【参考方案1】:出现此问题是因为您使用要获取的提供者的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));
);
【讨论】:
非常非常好!!!现在它完美地工作了......非常感谢我使用我自己的MyApp
小部件和我的模型类 Counter
,所以它看起来像这样:final BuildContext childContext = tester.element(find.byType(MyApp));
和expect(Provider.of<Counter>(childContext).value, 0);
以上是关于单元测试 -> 在此 ChangeNotifierProvider<Counter> 小部件上方找不到正确的 Provider<Counter>的主要内容,如果未能解决你的问题,请参考以下文章