【问题标题】:'Null' is not a subtype of type 'Future<Either<Failure, NumberTrivia>>'“Null”不是“Future<Either<Failure, NumberTrivia>>”类型的子类型
【发布时间】:2021-10-20 21:42:26
【问题描述】:

我正在通过以下视频在 TDD Clean Architecture 中实现颤振项目:https://www.youtube.com/watch?v=lPkWX8xFthE&t=1s

我的代码:

class MockNumberTriviaRepository extends Mock
    implements NumberTriviaRepository {}

void main() {
  late MockNumberTriviaRepository mockNumberTriviaRepository;
  late GetConcreteNumberTrivia usecase;

  setUp(() {
    mockNumberTriviaRepository = MockNumberTriviaRepository();
    usecase = GetConcreteNumberTrivia(mockNumberTriviaRepository);
  });

  final tNumber = 1;
  final tNumberTrivia = NumberTrivia(text: 'test', number: 1);

  test(
    'should get trivia for the number from the repository',
    () async {
      //arrange
      when( mockNumberTriviaRepository.getConcreteNumberTrivia(1)).thenAnswer((_) async {
        return Right(tNumberTrivia);
      });

      //act
      final result = await usecase.execute(number: 10);

      //assert
      expect(result, Right(tNumberTrivia));
      verify(mockNumberTriviaRepository.getConcreteNumberTrivia(tNumber));
      verifyNoMoreInteractions(mockNumberTriviaRepository);
    },
  );
} 

运行测试时,结果总是如下

package:number_trivia/features/number_trivia/domain/repositories/number_trivia_repository.dart 7:41  MockNumberTriviaRepository.getConcreteNumberTrivia
test\features\number_trivia\domain\usecases\get_concrete_number_trivia_test.dart 27:40               main.<fn>
test\features\number_trivia\domain\usecases\get_concrete_number_trivia_test.dart 25:5                main.<fn>

type 'Null' is not a subtype of type 'Future<Either<Failure, NumberTrivia>>'

这里显示错误:

abstract class NumberTriviaRepository{
  Future<Either<Failure, NumberTrivia>> getConcreteNumberTrivia(int number);
}
class GetConcreteNumberTrivia {
 final NumberTriviaRepository repository;

 GetConcreteNumberTrivia(this.repository);

 Future<Either<Failure, NumberTrivia>> execute({required int number}) async {
   return await repository.getConcreteNumberTrivia(number);
 }
}

请给我一些前进的解决方案。

【问题讨论】:

    标签: flutter testing tdd flutter-test clean-architecture


    【解决方案1】:

    这里是 ResoCoder TDD Course null-safety 版本。

    ResoCoder TDD Course (Null-safety)

    如果有帮助,请告诉我。

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
    【解决方案2】:

    我在学习本教程时遇到了同样的问题。问题来自 Dart 的空安全类型系统。因此,mockito 到存根方法的机制无法正常工作。基本上,您需要一个支持不可为空类型的模拟类。

    有两种方法:

    1. 使用 build_runner 包生成模拟类或
    2. 手动实现模拟类

    我遵循了第一个方法,它对我有用。只需在 dev_dependencies 下的 pubspec.yaml 中添加 build_runner 并执行 pub get。然后,您需要在测试中使用 @GenereateMocks([NumberTriviaRepository]) 注释您的主方法。

    之后,你需要在终端执行命令“flutter pub run build_runner build”(我直接在Android Studio中使用终端),然后它会为你构建模拟类,可以在同一个包中找到作为您的测试文件。模拟类的名称为 MockNumberTriviaRepository。

    我在这里找到了这些方法:https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md

    我的测试代码:

    @GenerateMocks([NumberTriviaRepository])
    void main() {
      late GetConcreteNumberTrivia useCase;
      late MockNumberTriviaRepository mockNumberTriviaRepository;
    
      setUp(() {
        mockNumberTriviaRepository = MockNumberTriviaRepository();
        useCase = GetConcreteNumberTrivia(mockNumberTriviaRepository);
      });
    
      final tNumber = 1;`enter code here`
      final tNumberTrivia = NumberTrivia(text: "Test", number: tNumber);
      // and so on like in the tutorial ...
    
    }
    

    我在 pubspec.yaml 中的 dev_dependencies:

    dev_dependencies:
        flutter_test:
            sdk: flutter
        mockito: ^5.0.15
        build_runner: ^2.1.2
    

    【讨论】:

      【解决方案3】:

      我遇到了同样的错误,我做了一些研究,最终对我有用。

      你需要“Null”检查,如果你遇到这样的错误。

      要使 Dart 将您的代码视为 null 安全的,SDK 约束必须要求具有 null 安全支持的语言版本。例如,您的 pubspec.yaml 文件可能具有以下约束:

      environment:
        sdk: ">=2.12.0 <3.0.0"
      

      您应该通过在类型名称后添加问号 (?) 来为变量指定可空类型

      abstract class NumberTriviaRepository {
          Future<Either<Failure, NumberTrivia>>? getConcreateNumberTrivia(int number);
          Future<Either<Failure, NumberTrivia>>? getRandomNumberTrivia();
      }
      

      调用时必须使用“NumberTriviaRepository”中的函数。

      class GetConcreateNumberTrivia {
        final NumberTriviaRepository repository;
      
        GetConcreateNumberTrivia(this.repository);
      
        Future<Either<Failure, NumberTrivia>?> execute({required int number}) async {
          return await repository.getConcreateNumberTrivia((number));
        }
      }
      

      我在下面添加了一些有用的链接。希望您的问题得到解决。

      Understanding null safety

      Sound null safety

      Practice with null safety

      【讨论】:

        【解决方案4】:

        这适用于最新的依赖项 (01/16/2022)。 2-3个错误的完整答案:

        添加:build_runner: ^2.1.7 到 pubspec.yaml

        //get_concrete_number_trivia_test
        
        //....
        import 'package:mockito/annotations.dart';
        class MockNumberTriviaRepository extends Mock implements NumberTriviaRepo {}
        
        @GenerateMocks([NumberTriviaRepo])
        void main() {
          late GetConcreteNumberTrivia usecases;
          late MockNumberTriviaRepository mockNumberTriviaRepository;
          late int tNumber;
          late NumberTrivia tNumberTrivia;
          setUp(() {
            mockNumberTriviaRepository = MockNumberTriviaRepository();
            usecases = GetConcreteNumberTrivia(repo: mockNumberTriviaRepository);
            tNumber = 1;
            tNumberTrivia = NumberTrivia(text: 'test', number: 1);
          });
        
          test('should get a trivia for the number from the repo', () async {
            // arrange
            when(mockNumberTriviaRepository.getConcreteNumberTrivia(tNumber))
                .thenAnswer((_) async => Right(tNumberTrivia));
            // act
            final result = await usecases.execute(number: tNumber);
            //assert
            expect(result, Right(tNumberTrivia));
            verify(mockNumberTriviaRepository.getConcreteNumberTrivia(tNumber));
            verifyNoMoreInteractions(mockNumberTriviaRepository);
          });
        }
        

        类 NumberTriviaRepository:

        abstract class NumberTriviaRepository {
          Future<Either<Failure, NumberTrivia>>? getConcreteNumberTrivia(int number);
          Future<Either<Failure, NumberTrivia>>? getRandomNumberTrivia();
        }
        

        类GetConcreteNumberTrivia:

        class GetConcreteNumberTrivia {
          final NumberTriviaRepository repo;
          GetConcreteNumberTrivia({
            required this.repo,
          });
        
          Future<Either<Failure, NumberTrivia>?> execute({required int number}) async {
            return await repo.getConcreteNumberTrivia(number);
          }
        }
        

        【讨论】:

          【解决方案5】:

          当你期待别的东西时它返回一个空值。你必须找到原因,为什么它返回一个空值。

          【讨论】:

          • 那是我无法识别的
          猜你喜欢
          • 2020-10-13
          • 1970-01-01
          • 1970-01-01
          • 2020-09-24
          • 2020-09-11
          • 2023-03-30
          • 2021-02-10
          • 1970-01-01
          • 2020-09-20
          相关资源
          最近更新 更多