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

723

Solution 1

Here is the ResoCoder TDD Course null-safety version.

ResoCoder TDD Course (Null-safety)

Let me know if it helps.

Solution 2

I faced the same error, I did some research and it finally worked for me.

You need to "Null" check, which if you encountered such an error.

To make Dart treat your code as null safe, the SDK constraints must require a language version that has null safety support. For example, your pubspec.yaml file might have the following constraints:

environment:
  sdk: ">=2.12.0 <3.0.0"

You should give the variable a nullable type by adding a question mark (?) after the type name

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

You have to use the functions in the "NumberTriviaRepository" when you call them.

class GetConcreateNumberTrivia {
  final NumberTriviaRepository repository;

  GetConcreateNumberTrivia(this.repository);

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

I added a few useful links below. I hope your problem is solved.

Understanding null safety

Sound null safety

Practice with null safety

Solution 3

I had the same Problem when following the tutorial. The Problem comes from Dart's null safety type system. Thus, the mechanisms of mockito to stub methods do not work properly. Basically, you need a mock class which supports non-nullable types.

There are two ways to this:

  1. Using the build_runner package to generate the mock class or
  2. Manually implement the mock class

I followed the first approch and it worked for me. Just add build_runner in your pubspec.yaml under dev_dependencies and execute pub get. Then you need to annotate your main-method in the test with @GenereateMocks([NumberTriviaRepository]).

Afterwards, you need to execute the command "flutter pub run build_runner build" in the terminal (I directly used the terminal in Android Studio) and then it will build the mock class for you, which can be found in the same package as your test file. The mocked class has the name MockNumberTriviaRepository.

I have found these approaches here: https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md

The code of my test:

@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 ...

}

My dev_dependencies in pubspec.yaml:

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

Solution 4

This worked for the latest dependencies (01/16/2022). Complete answer for 2-3 errors:

added: build_runner: ^2.1.7 to 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);
  });
}

class NumberTriviaRepository:

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

class GetConcreteNumberTrivia:

class GetConcreteNumberTrivia {
  final NumberTriviaRepository repo;
  GetConcreteNumberTrivia({
    required this.repo,
  });

  Future<Either<Failure, NumberTrivia>?> execute({required int number}) async {
    return await repo.getConcreteNumberTrivia(number);
  }
}
Share:
723
Akila Ishan
Author by

Akila Ishan

Updated on December 31, 2022

Comments

  • Akila Ishan
    Akila Ishan over 1 year

    I am implementing the flutter project in TDD Clean Architecture by following this video: https://www.youtube.com/watch?v=lPkWX8xFthE&t=1s

    my code:

    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);
        },
      );
    } 
    

    when running the test it always comes results as

    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>>'
    

    it shows an error here:

    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);
     }
    }
    

    Please give me some solution to move forward.

  • Akila Ishan
    Akila Ishan over 2 years
    Thats what I cannot identify
  • Dom
    Dom over 2 years
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review