Search code examples
flutterdarttestingriverpod

How do you correctly override an auto generated Riverpod NotifierProvider for testing?


import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'fake_test.g.dart';

@riverpod
class TheNumber extends _$TheNumber {
  @override
  int build() {
    return 42;
  }
}

class TheNumberWidget extends ConsumerWidget {
  const TheNumberWidget({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final theNumber = ref.watch(theNumberProvider);

    return Text('TheNumber: $theNumber');
  }
}

@riverpod
class FakeNumber extends _$FakeNumber {
  @override
  int build() {
    return 43;
  }
}

void main() {
  group(
    'TheNumber Tests',
    () {
      testWidgets(
        'Testing TheNumber',
        (tester) async {
          await tester.pumpWidget(
            ProviderScope(
              overrides: [
                theNumberProvider.overrideWith(
                  (ref) {
                    // THIS throws: "The argument type 'TheNumber Function(dynamic)' can't be assigned to the parameter type 'TheNumber Function()'"
                    return FakeNumber();
                  },
                ),
              ],
              child: ...
            ),
          );
        },
      );
    },
  );
}

I'm writing tests for my app but hit a road block while testing the ConsumerWidgets.

I tried different things like returning the mock value directly and building an Object that implements the generated AutoDisposeNotifier but nothing worked.


Solution

  • The Error you got tells you that dart expects a function without parameters that returns the type TheNumber. You gave it a function with the parameter ref and because dart doesn't expect a parameter it can not infer its type, there for it sees it as dynamic. We can just remove the ref:

    ProviderScope(
                  overrides: [
                    theNumberProvider.overrideWith(() => FakeNumber()),
                  ],
                  child: ...
                ),
    

    We also see that the expected type is TheNumber which is not the type of FakeNumber. We need to make FakeNumber implement TheNumber:

    @riverpod
    class FakeNumber extends _$FakeNumber implements TheNumber {
      @override
      int build() {
        return 43;
      }
    }
    

    Then your test should run and any Widget reading theNumberProvider will receive 43 instead of 42.