bloc unit testing: should do the following in order expected

Created on 14 Apr 2020  ·  6Comments  ·  Source: felangel/bloc

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?

question

All 6 comments

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

krusek picture krusek  ·  3Comments

ricktotec picture ricktotec  ·  3Comments

hivesey picture hivesey  ·  3Comments

abinvp picture abinvp  ·  3Comments

1AlexFix1 picture 1AlexFix1  ·  3Comments