我有这个使用 Equatable 和 Oxidized 包的 Dart 代码:
import 'package:equatable/equatable.dart';
import 'package:oxidized/oxidized.dart';
abstract class Failure {}
class NumberTriviaEntity extends Equatable {
final int number;
final String text;
const NumberTriviaEntity({required this.number, required this.text});
@override
List<Object?> get props => [text,number];
}
abstract interface class NumberTriviaIntf {
Future<Result<NumberTriviaEntity, Failure>> getConcreteNumberTrivia(int number);
Future<Result<NumberTriviaEntity, Failure>> getRandomNumberTrivia();
}
final class ConcreteNumberUseCase {
final NumberTriviaIntf repository;
const ConcreteNumberUseCase(this.repository);
Future<Result<NumberTriviaEntity, Failure>> execute({required int number}) async {
return await repository.getConcreteNumberTrivia(number);
}
}
我正在使用 Mockito 包对 NumberTriviaIntf 接口进行测试:
class MockNumberTriviaIntf extends Mock implements NumberTriviaIntf {}
class MockFailure extends Mock implements Failure {}
void main() {
group('ConcreteNumberUseCase', () {
late MockNumberTriviaIntf repository;
late ConcreteNumberUseCase useCase;
setUp(() {
repository = MockNumberTriviaIntf();
useCase = ConcreteNumberUseCase(repository);
});
test('returns Ok with valid data', () async {
// Arrange
const number = 42;
const Result<NumberTriviaEntity,Failure> entity = Ok(NumberTriviaEntity(number: number, text: 'Santi-U'));
when(repository.getConcreteNumberTrivia(number)).thenAnswer((_) async => entity);
// Act
final result = await useCase.execute(number: number);
// Assert
expect(result, entity);
verify(repository.getConcreteNumberTrivia(number));
verifyNoMoreInteractions(repository);
});
test('returns Err with failure', () async {
// Arrange
const number = 43;
final Result<NumberTriviaEntity,Failure> error = Err(MockFailure());
});
});
}
但我总是在这一行收到以下错误消息:
when(repository.getConcreteNumberTrivia(number)).thenAnswer((_) async => entity)
type 'Null' is not a subtype of type 'Future<Result<NumberTriviaEntity, Failure>>'
MockNumberTriviaIntf.getConcreteNumberTrivia
main.<fn>.<fn>
✖ ConcreteNumberUseCase returns Ok with valid data
✓ ConcreteNumberUseCase returns Err with failure
Exited (1)
有什么问题吗?
首先,我感谢@jamesdlin 的帮助。这是解决方案(适用于 Mockito 5.4.2、Dart 3.1.3):
@GenerateNiceMocks([MockSpec<NumberTriviaIntf>(), MockSpec<Failure>()])
import 'concrete_number_usecase_test.mocks.dart';
typedef TriviaEntityResult = Result<NumberTriviaEntity,Failure>;
void main() {
group('ConcreteNumberUseCase', () {
late MockNumberTriviaIntf repository;
late ConcreteNumberUseCase useCase;
setUp(() {
repository = MockNumberTriviaIntf();
useCase = ConcreteNumberUseCase(repository);
provideDummy(Result<NumberTriviaEntity, Failure>.err(MockFailure()));
});
// Helper method for verification
void verifyExecute(int number, TriviaEntityResult result, TriviaEntityResult expectedResult) {
expect(result, expectedResult);
verify(repository.getConcreteNumberTrivia(number));
verifyNoMoreInteractions(repository);
}
test('returns Ok with valid data', () async {
// Arrange
const number = 42;
const TriviaEntityResult expectedResult = Ok(NumberTriviaEntity(number: number, text: 'Santi-U'));
when(repository.getConcreteNumberTrivia(any)).thenAnswer((_) async => expectedResult);
// Act
final result = await useCase(number: number);
// Assert
verifyExecute(number, result, expectedResult);
});
test('returns Err with failure', () async {
// Arrange
const number = 43;
final TriviaEntityResult error = Err(MockFailure());
when(repository.getConcreteNumberTrivia(any)).thenAnswer((_) async => error);
// Act
final result = await useCase(number: number);
// Assert
verifyExecute(number, result, error);
});
});
}