Как издеваться над StateNotifier во флаттере / Riverpod
Я написал простой провайдер во флаттере, который должен предоставлять текущую дату/время (clock.now() из пакета часов):
final clockProvider = StateNotifierProvider<Clock, DateTime>((ref) {
return Clock();
});
class Clock extends StateNotifier<DateTime> {
late final Timer _timer;
Clock() : super(clock.now()) {
_timer = Timer.periodic(const Duration(seconds: 1), (_) {
state = clock.now();
});
}
@override
void dispose() {
_timer.cancel();
super.dispose();
}
}
Одна из причин этого заключается в том, что я думал, что таким образом будет проще протестировать заданное время с помощью Mockito:
@GenerateNiceMocks([
MockSpec<Clock>(),
])
void main() {
testWidgets(
"test clock", (tester) async {
// arrange
final MockClock mockClock = MockClock();
when(mockClock.state).thenReturn(DateTime(2000));
final container = ProviderContainer(
overrides: [
clockProvider.overrideWithValue(mockClock),
],
);
await container.pump();
final result = container.read(clockProvider);
});
Это вызывает следующее исключение:
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following ProviderException was thrown running a test:
An exception was thrown while building StateNotifierProvider<Clock, DateTime>#0cdfd.
Thrown exception:
Bad state: Tried to read the state of an uninitialized provider
При следовании этому подходу и перезаписи не значением, а провайдером сообщение об ошибке такое же, и флаттер по-прежнему жалуется на «Пытался прочитать состояние неинициализированного провайдера»:
final MockClock mockClock = MockClock();
when(mockClock.state).thenReturn(DateTime(2000));
final mockClockProvider = StateNotifierProvider<Clock, DateTime>((ref) {
return mockClock;
});
final container = ProviderContainer(
overrides: [
clockProvider.overrideWithProvider(mockClockProvider),
],
);
Буду признателен за любую помощь в поиске ошибки!
1 ответ
Если вы хотите протестировать с заданным временем, подход, который вы связали, в основном делает это, предоставляя аргументы для вашего конструктора. В вашем случае это будет что-то вроде
class ClockNotifier extends StateNotifier<DateTime> {
late final Timer _timer;
ClockNotifier(Clock clock = clock.now()) : super(clock) {
_timer = Timer.periodic(const Duration(seconds: 1), (_) {
state = clock.now();
});
}
Примечание: выполнениеstate = clock.now();
вTimer.periodic()
переопределит все, что вы установили в конструкторе. Но это может не повлиять на ваш тест.
Второе примечание: вы должны переименовать его в ClockNotifier, так как вы используете пакет Clock.
Надеюсь, это поможет, я занимаюсь Flutter всего несколько месяцев.