I am trying to do unit test on my bloc pattern in my flutter application. This is my bloc mapEventToState function:
@override
FoursquareState get initialState => Empty();
@override
Stream<FoursquareState> mapEventToState(
FoursquareEvent event,
) async* {
if (event is GetVenuesByUserEvent) {
yield Loading();
try {
final result = await repo.getVenuesByUser(event.lat, event.lng);
yield Loaded(result);
} on Exception catch (e) {
yield Error(e.toString());
}
}
}
As you can see i have Empty(), Loading(),Loaded() and Error() state.
I want to test my bloc when repo.getVenuesByUser(event.lat, event.lng) throw error so I write this unit test:
test(
'should emit [Loading, Error] when getting data fails ',
() async {
//arrange
when(repository.getVenuesByUser(lat, lng))
.thenThrow(NotFoundException("NotFOund"));
//act
bloc.add(GetVenuesByUserEvent(lat, lng));
//assert
final expect = [Empty(),Loading(), Error("msg")];
expectLater(bloc, emitsInOrder(expect));
},
);
but my test is fielded and i got error:
Expected: should do the following in order:
• emit an event that Empty:<Empty>
• emit an event that Loading:<Loading>
• emit an event that Error:<Error>
Actual: <Instance of 'FoursquareBloc'>
Which: emitted • Empty
• Loading
• Error
which didn't emit an event that Error:<Error>
package:test_api expectLater
package:flutter_test/src/widget_tester.dart 271:10 expectLater
test/block/foursquare_bloc_test.dart 78:9 main.<fn>.<fn>
dart:async _AsyncAwaitCompleter.start
test/block/foursquare_bloc_test.dart 70:7 main.<fn>.<fn>
Where is my mistake?
Hi @tazik561 👋
Thanks for opening an issue!
I believe the problem is in your expectLater you are expecting an error with the string "msg" whereas in the stub for the repository you have thenThrow(NotFoundException("NotF0und")).
That's going to cause the test to fail because the two error messages are different.
On another note, if you haven't already you might want to consider using bloc_test to help simplify your tests.
Hope that helps 👍
This is Error State :
class Error extends FoursquareState {
final String msg;
Error(this.msg);
@override
List<Object> get props => [msg];
}
And This is my Custom exception :
class AppException implements Exception {
final _message;
final _prefix;
AppException([this._message, this._prefix]);
String toString() {
return "$_prefix$_message";
}
}
class NotFoundException extends AppException {
NotFoundException([String msg]) : super(msg, "Not Found ");
}
In Error state I want to show a custom message to user so How can i handle it ?And how could i pass the test ? If i remove Error the test is passed but I think it is not right.
@tazik561 can you share a link to the repo?
I send project to your email now .Thanks for helping
@tazik561 you just need to expect:
final expect = [Empty(), Loading(), Error('Not Found NotFOund')];
It's because the bloc is just calling toString on the error and passing the string into the Error state.
In this case, NotFoundException("NotFOund").toString() results in 'Not Found NotFOund'.
thanks sir