如何正确覆盖自动生成的 Riverpod NotifierProvider 进行测试?

Vin*_*lin 1 testing dart flutter riverpod

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: ...
            ),
          );
        },
      );
    },
  );
}
Run Code Online (Sandbox Code Playgroud)

我正在为我的应用程序编写测试,但在测试 ConsumerWidgets 时遇到了障碍。

我尝试了不同的方法,例如直接返回模拟值并构建一个实现生成的 AutoDisposeNotifier 的对象,但没有任何效果。

小智 5

您收到的错误告诉您 dart 需要一个不带参数的函数,该函数返回 TheNumber 类型。你给它一个带有参数的函数ref,因为 dart 不需要参数,所以它无法推断它的类型,因此它将它视为dynamic. 我们可以删除引用:

ProviderScope(
              overrides: [
                theNumberProvider.overrideWith(() => FakeNumber()),
              ],
              child: ...
            ),
Run Code Online (Sandbox Code Playgroud)

我们还看到预期的类型是TheNumberwhich 不是 的类型FakeNumber。我们需要FakeNumber实施TheNumber

@riverpod
class FakeNumber extends _$FakeNumber implements TheNumber {
  @override
  int build() {
    return 43;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后您的测试应该运行,并且任何读取 NumberProvider 的 Widget 将收到 43 而不是 42。