Hello,
I am trying to use mocktail in a pure dart lib however, I am getting a weird behavior when verifying a call with a generic parameter type.
I have a simplified version of DartZ/Either, with names changed and just the fold and check type methods.
abstract class Result<Exception, S> {...}
class Failure<Exception, S> extends Result<Exception, S> {...}
class Success<Exception, S> extends Result<Exception, S> {...}
Then I want to check if the output class was called with one of the specified types (Success or Failure).
I first add the fallbacks and set up the mocks
final genericException = Exception('ERROR');
// Output parameters
final outputParameterSuccess = Success<Exception, CatOutputDTO>(
CatOutputDTO());
final outputParameterFailure =
Failure<Exception, CatOutputDTO>(genericException);
setUpAll(() {
// fallback values for output call
registerFallbackValue(outputParameterSuccess);
registerFallbackValue(outputParameterFailure);
});
setUp(() {
mockedRepository = MockCatRepository();
output = MockGetCatOutput();
useCase = GetCatUseCase(mockedRepository, output);
});
The failure test:
test('Should call the output with Failure if the repository returned Failure',
() async {
// Arrange / Given
// stub the repository call, returning a Failure
when(() => mockedRepository.getCat())
.thenAnswer((_) async => repositoryResultFailure);
// stub the output call, return true (meaning executed with success);
when(() => output.call(any())).thenAnswer((_) async => true);
// Act / When
await useCase.call();
// Assert / Expect
// Verify the output was called once
verify(() => output.call(outputParameterFailure)).called(1);
});
This works fine, since the repository is returning a Failure, the output should be called with a Failure, for example, if I change the verify from outputParameterFailure
to outputParameterSuccess
, it fails, since the type doesn't match the call made.
The return from the output doesn't matter for me, just the parameter being passed.
Now, this gets weird when I try to test the Success case, when the repository returns a Success, my useCase should call the output with a Success too. So:
test('Should call the output with Success if the repository returned Success',
() async {
// Arrange / Given
// stub the repository call, returning a Failure
when(() => mockedRepository.getCat())
.thenAnswer((_) async => repositoryResultSuccess);
// stub the output call with anything
when(() => output.call(any())).thenAnswer((_) async => true);
// Act / When
await useCase.call();
print("outputParameterSuccess: " + outputParameterSuccess.toString());
// Assert / Expect
// Verify the output was called once
verify(() => output.call(outputParameterSuccess)).called(1);
});
The error I get is the weird thing itself.
00:01 +2: test/usecases/get_cat_test.dart: Should call the output with Success if the repository returned Success
outputParameterSuccess: Success(Instance of 'CatOutputDTO')
00:01 +2 -1: test/usecases/get_cat_test.dart: Should call the output with Success if the repository returned Success [E]
No matching calls. All calls: MockGetCatOutput.call(Success(Instance of 'CatOutputDTO'))
(If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
package:test_api fail
package:mocktail/src/mocktail.dart 723:7 _VerifyCall._checkWith
package:mocktail/src/mocktail.dart 516:18 _makeVerify.<fn>
test/usecases/get_cat_test.dart 92:11 main.<fn>
The UseCase:
class GetCatUseCase implements GetCat {
final CatDataAccess catDataAccess;
final GetCatOutput output;
GetCatUseCase(this.catDataAccess, this.output);
@override
Future<bool> call() async {
var result = await catDataAccess.getCat();
await result.fold(
(failure) async => await output.call(Failure(failure)),
(success) async => await output.call(Success(success.parseAsOutputDTO())),
);
return result.isSuccess();
}
}
The use case is calling the output correctly, and even the output confirms it at All calls: MockGetCatOutput.call(Success(Instance of 'CatOutputDTO'))
. The print output placed there, also outputs the same instance type. However, the test fails.
I suspect the motive behind the test passing with Failure is because Failure(Exception)
isn't generic, and Success(T)
is? Maybe I am doing something wrong or missing something important?
I also suspect a bit about the Result<Exception, CatOutputDTO>
type expected when veryfing with verify(() => output.call(outputParameterSuccess)).called(1);
... It might be expecting the Result<Exception, CatOutputDTO>
, but instead getting the Success(Instance of 'CatOutputDTO')
? It's a little weird for me.
The Output class is structure as follow:
class MockGetCatOutput extends Mock
implements GetCatOutput {}
abstract class GetCatOutput
implements OutputBoundary<CatOutputDTO> {}
abstract class OutputBoundary<SuccessType> {
Future<bool> call(Result<Exception, SuccessType> result);
}
Thank you all in advance.