测试 Riverpod StateNotifierProvider
一个关于在使用 riverpod StateNotifierProvider 时如何模拟状态以测试小部件的示例。
这些测试无需 Mocktail / Mockito 即可运行
快速详情
- Model: 使用 Freezed 创建的 Counter 类
- State: CounterNotifier 继承自 StateNotifier
- Provider: counterProvider 是一个 StateNotifierProvider
StateNotifierProvider 可测试性的重要性
在测试 Flutter 小部件时,我们可能希望模拟一个预定义的状态,以便测试小部件在给定状态下的渲染方式。例如,一个小部件可能需要根据用户角色显示或隐藏,而用户角色可能是存储在状态中的用户对象的一部分。我们的测试可以确保这种重要的条件渲染不会因未来的代码更改而中断。
在这个简化的示例中,我们使用一个计数器来测试当计数为偶数时小部件是否呈现。
该存储库作为一个示例,展示了如何构建你的 StateNotifier 及其构造函数,以便测试小部件可以使用模拟的 provider 和预定义的状态。
下面是对该存储库中发生情况的细分。
解释
测试小部件
Widget isEvenTestWidget(StateNotifierProvider<CounterNotifier, Counter> mockProvider) {
return ProviderScope(
overrides: [
counterProvider.overrideWithProvider(mockProvider),
],
child: const MaterialApp(
home: ScreenHome(),
),
);
}
我们主屏幕的这个测试小部件使用 ProviderScope() 的 overrides 属性来覆盖小部件中使用的 provider。
当 home.dart 的 ScreenHome() 小部件调用 Counter counter = ref.watch(counterProvider); 时,它将使用我们的 mockProvider 而不是“真实”的 provider。
isEvenTestWidget() 的 mockProvider 参数与 counterProvider() 的“类型”相同。
测试
testWidgets('If count is even, IsEvenMessage is rendered.', (tester) async {
// Mock a provider with an even count
final mockCounterProvider =
StateNotifierProvider<CounterNotifier, Counter>((ref) => CounterNotifier(counter: const Counter(count: 2)));
await tester.pumpWidget(isEvenTestWidget(mockCounterProvider));
expect(find.byType(IsEvenMessage), findsOneWidget);
});
在测试中,我们创建一个 mockProvider,其中包含我们需要用于测试 ScreenHome() 小部件渲染的预定义值。在此示例中,我们的 provider 使用 **状态** count: 2 进行初始化。
我们正在测试 isEvenMessage() 小部件是否以偶数(2)渲染。另一项测试则测试当计数为奇数时该小部件不渲染。
StateNotifier 构造函数
class CounterNotifier extends StateNotifier<Counter> {
CounterNotifier({Counter counter = const Counter(count: 0)}) : super(counter);
void increment() {
state = state.copyWith(count: state.count + 1);
}
}
为了能够使用预定义状态创建 mockProvider,重要的是 StateNotifier (counter_state.dart) 构造函数包含一个可选的状态模型参数。 **默认参数** 是状态应正常初始化的方式。我们的测试可以 **选择性地** 提供一个用于测试的指定状态,该状态将传递给 super()。
Build Runner
需要代码生成器来生成 freezed 类代码
$ flutter pub run build_runner build --delete-conflicting-outputs