Invalid argument event trying unit test flutter with Mockito - flutter

Event i trying to flutter test, i get issue's invalid argument, in other case i explain same method to testing and result running as well, but i don't what a mockito mean at the issue's cause in other case i success with same method, let see my fetch test with mockito :
testing
test('should return list of tv/on_the_airs when response code is 200 ',
() async {
// arrange
when(mockHttpClient.get(Uri.parse('$BASE_URL/tv/top_rated?$API_KEY')))
.thenAnswer((_) async => http.Response(
'{"page": 1,"results": [ {"backdrop_path": "/4sSzTvk200BQyYjRJq69mLwE9xG.jpg","first_air_date": "2018-04-25","genre_ids": [16,35,18,10759],"id": 79141,"name": "Scissor Seven","origin_country": ["CN"],"original_language": "zh","original_name": "刺客伍六七","overview": "Seeking to recover his memory, a scissor-wielding, hairdressing, bungling quasi-assassin stumbles into a struggle for power among feuding factions.","popularity": 76.07,"poster_path": "/A39DWUIrf9WDRHCg7QTR8seWUvi.jpg","vote_average": 8.8,"vote_count": 457},],"total_pages": 125,"total_results": 2496}',
200));
// act
final result = await dataSource.getTopRatedTvSeriess();
// assert
expect(result, tTvSeriesList);
});
then i have error:
Invalid argument (string): Contains invalid characters.: "{\"page\": 1,\"results\": [ {\"backdrop_path\": \"/4sSzTvk200BQyYjRJq69mLwE9xG.jpg\",\"first_air_date\": \"2018-04-25\",\"genre_ids\": [16,35,18,10759],\"id\": 79141,\"name\": \"Scissor Seven\",\"origin_country\": [\"CN\"],\"original_language\": \"zh\",\"original_name\": \"刺客伍六七\",\"overview\": \"Seeking to recover his memory, a scissor-wielding, hairdressing, bungling quasi-assassin stumbles into a struggle for power among feuding factions.\",\"popularity\": 76.07,\"poster_path\": \"/A39DWUIrf9WDRHCg7QTR8seWUvi.jpg\",\"vote_average\": 8.8,\"vote_count\": 457},],\"total_pages\": 125,\"total_results\": 2496}"

Related

Flutter Future timeouts not always working correctly

Hey I need some help here for How to use timeouts in flutter correctly. First of all to explain what the main goal is:
I want to recive data from my Firebase RealTime Database but need to secure this request api call with an time out of 15 sec. So after 15 sec my timeout should throw an exception that will return to the Users frontend the alert for reasons of time out.
So I used the simple way to call timeouts on future functions:
This functions should only check if on some firebase node an ID is existing or not:
Inside this class where I have declared this functions I also have an instance which called : timeoutControl this is a class which contains a duration and some reasons for the exceptions.
Future<bool> isUserCheckedIn(String oid, String maybeCheckedInUserIdentifier, String onGateId) async {
try {
databaseReference = _firebaseDatabase.ref("Boarding").child(oid).child(onGateId);
final snapshot = await databaseReference.get().timeout(Duration(seconds: timeoutControl.durationForTimeOutInSec), onTimeout: () => timeoutControl.onEppTimeoutForTask());
if(snapshot.hasChild(maybeCheckedInUserIdentifier)) {
return true;
}
else {
return false;
}
}
catch (exception) {
return false;
}
}
The TimeOutClass where the instance timeoutControl comes from:
class CustomTimeouts {
int durationForTimeOutInSec = 15; // The seconds for how long to try until we throw an timeout exception
CustomTimeouts();
// TODO: Implement the exception reasons here later ...
onEppTimeoutForUpload() {
throw Exception("Some reason ...");
}
onEppTimeoutForTask() {
throw Exception("Some reason ...");
}
onEppTimeoutForDownload() {
throw Exception("Some reason ...");
}
}
So as you can see for example I tried to use this implementation above. This works fine ... sometimes I need to fight with un explain able things -_-. Let me try to introduce what in somecases are the problem:
Inside the frontend class make this call:
bool isUserCheckedIn = await service.isUserCheckedIn(placeIdentifier, userId, gateId);
Map<String, dynamic> data = {"gateIdActive" : isUserCheckedIn};
/*
The response here is an Custom transaction handler which contains an error or an returned param
etc. so this isn't relevant for you ...
*/
_gateService.updateGate(placeIdentifier, gateId, data).then((response) {
if(response.hasError()) {
setState(() {
EppDialog.showErrorToast(response.getErrorMessage()); // Shows an error message
isSendButtonDiabled = false; /*Reset buttons state*/
});
}
else {
// Create an gate process here ...
createGateEntrys(); // <-- If the closures update was successful we also handle some
// other data inside the RTDB for other reasons here ...
}
});
IMPORTANT to know for you guys is that I am gonna use the returned "boolean" value from this function call to update some other data which will be pushed and uploaded into another RTDB other node location for other reasons. And if this was also successful the application is going on to update some entrys also inside the RTDB -->createGateEntrys()<-- This function is called as the last one and is also marked as an async function and called with its closures context and no await statement.
The Data inside my Firebase RTDB:
"GateCheckIns" / "4mrithabdaofgnL39238nH" (The place identifier) / "NFdxcfadaies45a" (The Gate Identifier)/ "nHz2mhagadzadzgadHjoeua334" : 1 (as top of the key some users id who is checked in)
So on real devices this works always without any problems... But the case of an real device or simulator could not be the reason why I'am faceing with this problem now. Sometimes inside the Simulator this Function returns always false no matter if the currentUsers Identifier is inside the this child nodes or not. Therefore I realized the timeout is always called immediately so right after 1-2 sec because the exception was always one of these I was calling from my CustomTimeouts class and the function which throws the exception inside the .timeout(duration, onTimeout: () => ...) call. I couldn't figure it out because as I said on real devices I was not faceing with this problem.
Hope I was able to explain the problem it's a little bit complicated I know but for me is important that someone could explain me for what should I pay attention to if I am useing timeouts in this style etc.
( This is my first question here on StackOverFlow :) )

Throw Exception in Flutter Test

I am following this tutorial for Clean Architecture in flutter
This is my test file
test(
'should return server failure when call to remote data is unsuccessful',
() async {
// arrange
when(mockRemoteDataSource.getConcreteNumberTrivia(any))
.thenThrow(ServerException());
// act
final result = await repository.getConcreteNumberTrivia(tNumber);
// assert
verify(mockRemoteDataSource.getConcreteNumberTrivia(tNumber));
verifyZeroInteractions(mockLocalDataSource); // <--- this line is failing
expect(result, equals(Left(ServerFailure()))); // // <--- this line is failing
},
);
This is my code
Future<Either<Failure, NumberTrivia>> getConcreteNumberTrivia(int number) async {
networkInfo.isConnected;
try {
final remoteTrivia = await remoteDataSource.getConcreteNumberTrivia(number);
localDataSource.cacheNumberTrivia(remoteTrivia);
return Right(remoteTrivia);
} on ServerException {
return Left(ServerFailure());
}
}
I dont know why but coz of these 2 lines, test case is failing.
verifyZeroInteractions(mockLocalDataSource);
expect(result, equals(Left(ServerFailure())));
I have mentioned in test case to throw a server exception using when and thenThrow but still it goes to this line localDataSource.cacheNumberTrivia(remoteTrivia);. I think this is the cause of the error but I am not quite sure.
I did read the docs but I could not find why is this problem occuring. What am i doing wrong? I am new to TDD in flutter. Thanks in advance :)
verifyZeroInteractions(mockLocalDataSource);
Fail is normal because you called it in you getConcreteNumberTrivia function (localDataSource.cacheNumberTrivia) and you are expecting in your test no interaction. Just remove it, it should pass.
expect(result, equals(Left(ServerFailure())));
For the this one, can you try this ?
result.fold((left) {
expect(left, isA<ServerFailure>());
}, (r) => fail("test failed"));

Using await for with streams and handling done + onError callbacks

I am using dart:io's HTTP client to download large files the following way:
final url = Uri.parse(fileUrl);
final request = await httpClient.getUrl(url);
final response = await request.close();
Then I use the response of type HttpClientResponse which implements Stream<List<int>>, where each emitted List<int> represents a chunk of the file being downloaded.
My aim is to "transform" that stream into another one and to do so, I have recently learned of await for + yield which allows to do just that:
Stream<Event> processResponse(HttpClientResponse response) async* {
await for (final List<int> chunk in response) {
yield Event.FileChunk(chunk: chunk);
}
yield const Event.Completed();
}
Initially, and before learning about await for, I intended to use the method Stream<T>.listen which takes 4 parameters:
the onData callback for each emitted value in the stream,
the onError callback to notify errors while emitting values,
the onDone callback to notify the stream is closing and won't be emitting any new values and finally
the cancelOnError boolean parameter that is self-explaining.
By using await for () {}, I believe I cover #1 and #3 since I'll get all emitted values and when done, the code will leave the await for's scope which should mean it's done.
But what about errors? Since these streams will be lengthy and heavy IO streams, surely there can be an IO error at any moment. How are they reported? How can I access their data in order to report those and debug if needed?
Just use good ol' try catch, see this reduced example:
Stream<int> inee()async*{
try{
for (int i = 0; i <= 5; i++) {
if(i==4)throw Exception('Hated number 4');
yield i;
}
}catch(e,st){
print('Catch exception $e');
yield 33;
} finally{
//cleanup of incomplete files
}
}
void main() {
inee().listen(print);
}
The output would be the following:
0
1
2
3
Catch exception Exception: Hated number 4
3
inside the catch you can still yield, log your exceptions . You can also add the logic to delete incomplete files to the finally block.

Flutter - Expected: should do the following in order: emits an event Empty, NumberTriviaError, Actual: Empty: Which was not a Stream or a SteamQue

I'm doing Flutter Clean Architecture TDD course from closely 20days. I'm writing unit test of Stream (mapEventToState) here is my Test code :
test(
'should emit [Error] when the input is invalid',
() async {
// arrange
when(mockInputConverter!.stringToUnsignedInteger(SIGNED_STRINGS))
.thenReturn(Left(InvalidInputFailure()));
// assert later
final expected = [
// The initial state is always emitted first
NumberTriviaEmpty(),
NumberTriviaError(message: INVALID_INPUT_FAILURE_MESSAGE),
];
expectLater(bloc!.state, emitsInOrder(expected));
// act
bloc!.add(GetTriviaForConcreteNumber(tNumberString));
},
);
Just forget all about (when), because It's fine I've mocked all classes and simply return a Left of Either which is obviously a Failure. So the problem rise in expected data, I just created list of expected and passed it inside the method the "expectLater" in order "emitsInOrder".
My Implementation code of Stream is is here :
#override
Stream<NumberTriviaState> mapEventToState(NumberTriviaEvent event,) async* {
if (event is GetTriviaForConcreteNumber) {
final inputEither =
inputConverter.stringToUnsignedInteger(event.numberString);
yield* inputEither!.fold(
(failure) async* {
yield NumberTriviaError(message: INVALID_INPUT_FAILURE_MESSAGE);
},
// Although the "success case" doesn't interest us with the current test,
// we still have to handle it somehow.
(integer) => throw UnimplementedError(),
);
}
The [ Error ] I have put in the Title isn't completed because It's a little bit long I'm sharing it here please take a look upon It what actually I'm doing wrong.
Expected: should do the following in order:
• emit an event that NumberTriviaEmpty:<NumberTriviaEmpty()>
• emit an event that NumberTriviaError:<NumberTriviaError(Invalid Input - The number must be a positive integer or zero.)>
Actual: NumberTriviaEmpty:<NumberTriviaEmpty()>
Which: was not a Stream or a StreamQueue
I have done all these the same, what it expect from me but still it's throwing this exception. I stuck in this error about 4 days I search everywhere but I didn't find any fix, Kindly If I'm doing something wrong just throw your recommendation in the comment section or Answer. Thank you :)
In addition to changing 'bloc!.state' to 'bloc' (per QuangNV and ouflak), try also changing the 'async' in your test to the asynchronous generator, 'async*', to match to the code used in your Stream implementation.
test(
'should emit [Error] when the input is invalid',
() async* {
// arrange
I used another way by using the bloc_test: ^8.0.0 package and the flutter_bloc: ^7.0.0
blocTest<NumberTriviaBloc, NumberTriviaState>(
'should emits [LoadingState, ErrorState(InputConvert failure..)] when add event [getConcreteNumberTrivia] with invaildString ',
build: () => numberTriviaBloc,
setUp: () => when(mockInputConverter.stringToUnsignedInteger(any))
.thenReturn(const Left(InvalidInputFailure())),
act: (bloc) =>
bloc.add(const GetConcreteNumberEvent(number: tNumberString)),
expect: () => [
LoadingState(),
ErrorState(message: const InvalidInputFailure().message)
],
);
So the complete answer is
You can try changing from:
expectLater(bloc!.state, emitsInOrder(expected));
To:
expectLater(bloc, emitsInOrder(expected));
In addition to changing 'bloc!.state' to 'bloc' (per QuangNV and ouflak), try also changing the 'async' in your test to the asynchronous generator, 'async*', to match to the code used in your Stream implementation.
test(
'should emit [Error] when the input is invalid',
() async* {
// arrange
You can try changing from:
expectLater(bloc!.state, emitsInOrder(expected));
To:
expectLater(bloc, emitsInOrder(expected));
Hope you can solve it!
I'm also following the same course & in addition of the ) async* { suggestion, I also needed to add quotation marks to have
yield Error(message: "INVALID_INPUT_FAILURE_MESSAGE");
In contrast,
expectLater(bloc.state,
expectLater(bloc!.state,
expectLater(bloc,
had not impact on passing the test successfully.

How to fake throwing an exception?

I have following setup
A.CallTo(() => fakeChargeService
.CreateAsync(A<ChargeCreateOptions>._, A<RequestOptions>._, A<CancellationToken>._))
.Throws<StripeException>((se) => stripeException);
and then I assert
var msg = await Assert.ThrowsAsync<StripeException>(async () => await mediator.Send(command, CancellationToken.None));
which eventually executes this piece of code
var policyResult = await Policy.Handle<StripeException>(x => x.ShouldRetry())
.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(0.5),
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
})
.ExecuteAndCaptureAsync(async () => await this.chargeService.CreateAsync(options, null, cancellationToken));
and here I get error
Assert.Throws() Failure
Expected: typeof(Stripe.StripeException)
Actual: typeof(FakeItEasy.Configuration.FakeConfigurationException): The faked method has the signature (Stripe.ChargeCreateOptions, Stripe.RequestOptions, System.Threading.CancellationToken), but throws was used with (Stripe.StripeException).
I am not sure what is it that I am doing wrong. Any help would be appreciated
You seem to be specifying the wrong signature in your Throws. CreateAsync takes (Stripe.ChargeCreateOptions, Stripe.RequestOptions, System.Threading.CancellationToken), but Throws was used with (Stripe.StripeException).
See the second example in Throwing Exceptions:
// Pass up to 4 original call argument values into the method that creates the exception.
A.CallTo(() => fakeShop.NumberOfSweetsSoldOn(A<DateTime>._))
.Throws((DateTime when)=>new InvalidDateException(when + " is in the future"));
Note that the signature of the lambda and the called method match.
You should update your lambda to match the proper signature. Or better yet, just replace with
.Throws<StripeException>(stripeException)
since there doesn't appear to be any reason to lazily throw, based on the snippet of code you provided.