Как издеваться над 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 всего несколько месяцев.

Другие вопросы по тегам