'Null' 不是类型 'Future<Either<Failure, NumberTrivia>>' 的子类型
'Null' is not a subtype of type 'Future<Either<Failure, NumberTrivia>>'
我正在按照以下视频在 TDD Clean Architecture 中实施 flutter 项目: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);
}
}
请给我一些继续前进的解决方案。
它 returns 为 null,而您期待其他东西。你必须找到原因,为什么它 returns 为 null。
我在学习教程时遇到了同样的问题。问题来自 Dart 的空安全类型系统。因此,mockito 到存根方法的机制无法正常工作。基本上,您需要一个支持不可空类型的模拟 class。
有两种方法:
- 使用 build_runner 包生成 mock class 或
- 手动实现模拟class
我遵循了第一种方法,它对我有用。只需在 dev_dependencies 下的 pubspec.yaml 中添加 build_runner 并执行 pub get。然后你需要在测试中用 @GenereateMocks([NumberTriviaRepository]).
注释你的主要方法
之后需要在终端中执行命令“flutter pub 运行 build_runner build”(我是直接用Android Studio中的终端)然后就可以build了模拟 class 给你,它可以在与你的测试文件相同的包中找到。模拟的 class 的名称为 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 ...
}
我的 dev_dependencies 在 pubspec.yaml:
dev_dependencies:
flutter_test:
sdk: flutter
mockito: ^5.0.15
build_runner: ^2.1.2
我遇到了同样的错误,我做了一些研究,最终对我有用。
你需要进行“Null”检查,如果你遇到这样的错误。
要使 Dart 将您的代码视为空安全,SDK 约束必须要求具有空安全支持的语言版本。例如,您的 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));
}
}
我在下面添加了一些有用的链接。希望你的问题得到解决。
这是 ResoCoder TDD 课程空安全版本。
ResoCoder TDD Course (Null-safety)
如果有帮助请告诉我。
这适用于最新的依赖项 (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);
});
}
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);
}
}
我正在按照以下视频在 TDD Clean Architecture 中实施 flutter 项目: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);
}
}
请给我一些继续前进的解决方案。
它 returns 为 null,而您期待其他东西。你必须找到原因,为什么它 returns 为 null。
我在学习教程时遇到了同样的问题。问题来自 Dart 的空安全类型系统。因此,mockito 到存根方法的机制无法正常工作。基本上,您需要一个支持不可空类型的模拟 class。
有两种方法:
- 使用 build_runner 包生成 mock class 或
- 手动实现模拟class
我遵循了第一种方法,它对我有用。只需在 dev_dependencies 下的 pubspec.yaml 中添加 build_runner 并执行 pub get。然后你需要在测试中用 @GenereateMocks([NumberTriviaRepository]).
注释你的主要方法之后需要在终端中执行命令“flutter pub 运行 build_runner build”(我是直接用Android Studio中的终端)然后就可以build了模拟 class 给你,它可以在与你的测试文件相同的包中找到。模拟的 class 的名称为 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 ...
}
我的 dev_dependencies 在 pubspec.yaml:
dev_dependencies:
flutter_test:
sdk: flutter
mockito: ^5.0.15
build_runner: ^2.1.2
我遇到了同样的错误,我做了一些研究,最终对我有用。
你需要进行“Null”检查,如果你遇到这样的错误。
要使 Dart 将您的代码视为空安全,SDK 约束必须要求具有空安全支持的语言版本。例如,您的 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));
}
}
我在下面添加了一些有用的链接。希望你的问题得到解决。
这是 ResoCoder TDD 课程空安全版本。
ResoCoder TDD Course (Null-safety)
如果有帮助请告诉我。
这适用于最新的依赖项 (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);
});
}
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);
}
}