[英]Riverpod - How to access a provider in a test?
我有這個片段:
final countProvider = StateProvider<int>((ref) {
return 0;
});
class CountWidget extends ConsumerWidget {
const CountWidget();
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(countProvider);
return Column(
children: [
Text(count.toString()),
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
ref.read(countProvider.notifier).state++;
},
),
],
);
}
}
這是一個非常簡化的代碼,但想法是它使用了 state 提供程序。
我想編寫一個測試並驗證,經過一些操作,提供程序位於特定的 state 中(不依賴於 UI,在這里我可以使用find.text()
,但我的 state 可能要復雜得多)。
在抽出我的小部件后,我想在我的測試中訪問 model:
await tester.pumpWidget(const CountWidget());
await tester.tap();
await tester.pump();
// ... Some other actions.
final currentCountState = // ?
expect(currentCountState, 3); // For example.
我怎樣才能做到這一點?
在這里, CountWidget
擴展了ConsumerWidget
,后者擴展了ConsumerStatefulWidget
,后者又擴展了StatefulWidget
。
在 riverpod 的代碼中,我們可以看到創建的 state 實際上是一個_ConsumerState
:
class _ConsumerState extends ConsumerState<ConsumerWidget> {
@override
WidgetRef get ref => context as WidgetRef;
@override
Widget build(BuildContext context) {
return widget.build(context, ref);
}
}
context
和ref
實際上是相同的 object。
這是因為在ConsumerStatefulWidget
中:
/// A [StatefulWidget] that can read providers.
abstract class ConsumerStatefulWidget extends StatefulWidget {
/// A [StatefulWidget] that can read providers.
const ConsumerStatefulWidget({Key? key}) : super(key: key);
@override
// ignore: no_logic_in_create_state
ConsumerState createState();
@override
ConsumerStatefulElement createElement() {
return ConsumerStatefulElement(this);
}
}
關聯元素(用於context
的元素是ConsumerStatefulElement
:
class ConsumerStatefulElement extends StatefulElement implements WidgetRef {
// ...
}
所以在測試中,你可以使用tester.element
來獲取ref
:
await tester.pumpWidget(const CountWidget());
await tester.tap();
await tester.pump();
// ... Some other actions.
final ref = tester.element<ConsumerStatefulElement>(find.byType(CountWidget));
final currentCountState = ref.read(countProvider);
expect(currentCountState, 3); // For example.
接受的答案有點 hacky,如果提供者在已被處置時被讀取,則會引發錯誤。 正確的方法是在測試中顯式使用ProviderContainer
和UncontrollerProviderScope
。 通過使用它,我們也可以在小部件之外使用提供程序。
// make sure riverpod is imported
import 'package:flutter_riverpod/flutter_riverpod.dart';
test('outside of widget', () {
final container = ProviderContainer(
overrides: [
// define your overrides here if required
]
);
final count = container.read(countProvider);
expect(count, 0);
});
testWidgets('Test the widget', () async {
final container = ProviderContainer();
await tester.pumpWidget(
UncontrolledProviderScope(
container: container,
child: const CountWidget(),
)
);
await tester.tap(find.byIcon(Icons.add));
final currentCount = container.read(countProvider);
expect(currentCount, 1);
});
參考:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.