Bloc: [Question] bloc test passes sometimes, fails sometimes?

Created on 7 Oct 2020  路  3Comments  路  Source: felangel/bloc

Hi,

I'm using flutter_bloc and fit_kit to pull some user data to display on my app. I had some issues with updating the state, sometimes it works and sometimes it didn't. So I wrote some tests to see and my tests pass sometimes and fail sometimes. Am I doing anything wrong here?

Bloc:

FitnessDataAuthenticationRepository repo;

  FitnessDataBloc({this.repo})
      : assert(repo != null),
        super(FitnessDataInitial());

@override
  Stream<FitnessDataState> mapEventToState(
    FitnessDataEvent event,
  ) async* {
    ...
    if (event is FetchFitnessData) {
      yield* _mapFetchFitnessDataToState(event);
    }
    ...
  }

  Stream<FitnessDataState> _mapFetchFitnessDataToState(
      FetchFitnessData event) async* {
    yield FitnessDataLoadingInProgress();
    try {
      final List days = await repo.getSteps(event.begin, event.end);
      yield days != null
          ? FitnessDataLoaded(
              days: days[0], aveSteps: days[1], totalSteps: days[2])
          : FitnessDataError();
    } catch (_) {
      yield FitnessDataError();
    }
  }

Repository:

class FitnessDataAuthenticationRepository {
  final FitnessApiClient fitnessApiClient;

  FitnessDataAuthenticationRepository({@required this.fitnessApiClient})
      : assert(fitnessApiClient != null);
    ...
  Future<List> getSteps(DateTime begin, DateTime end) async {
    return fitnessApiClient.readStepsOnly(begin: begin, end: end);
  }
}

ApiClient:

class FitnessApiClient {
  Future<List> readStepsOnly({DateTime begin, DateTime end}) async {
    try {
      bool perm = await FitKit.requestPermissions([DataType.STEP_COUNT]);
      if (perm) {
        try {
          steps = await FitKit.read(
            DataType.STEP_COUNT,
            dateFrom: DateTime.now().subtract(Duration(days: 30)),
            dateTo: DateTime.now(),
          );
          ...
          ...
        } catch (e) {
          throw Exception(e);
        }
      } else {
        print("dont have permission for fitness data");
      }
    } catch (e) {
      throw Exception(e);
    }
    return [plotPoints, ave, total];
  }
}

the test:

group("FitnessDataBloc", () {
    setUp(() {
      mockFitnessDataAuthenticationRepository =
          MockFitnessDataAuthenticationRepository();
      fitnessDataBloc =
          FitnessDataBloc(repo: mockFitnessDataAuthenticationRepository);
    });

    tearDown(() {
      fitnessDataBloc?.close();
    });

    group("FetchFitnessData", () {
      List<FlSpot> plotPoints = [FlSpot(0, 0)];
      List tst = [plotPoints, 1000, 1000];
      blocTest(
        "emits [FitnessDataLoaded] when request for fitness data",
        build: () {
          when(mockFitnessDataAuthenticationRepository.getSteps(
                  DateTime.now(), DateTime.now()))
              .thenAnswer((_) => Future.value(tst));
          return fitnessDataBloc;
        },
        act: (bloc) => bloc
            .add(FetchFitnessData(begin: DateTime.now(), end: DateTime.now())),
        expect: [
          FitnessDataLoadingInProgress(),
          FitnessDataLoaded(days: tst[0], totalSteps: tst[1], aveSteps: tst[2]),
        ],
      );
    });

And the error that I get sometimes:

package:test_api                             expect
package:bloc_test/src/bloc_test.dart 167:9   runBlocTest.<fn>
===== asynchronous gap ===========================
dart:async                                   _asyncThenWrapperHelper
package:bloc_test/src/bloc_test.dart         runBlocTest.<fn>
dart:async                                   runZoned
package:bloc_test/src/bloc_test.dart 150:9   runBlocTest
package:bloc_test/src/bloc_test.dart 122:11  blocTest.<fn>

Expected: [
            FitnessDataLoadingInProgress:FitnessDataLoadingInProgress,
            FitnessDataLoaded:FitnessDataLoaded
          ]
  Actual: [
            FitnessDataLoadingInProgress:FitnessDataLoadingInProgress,
            FitnessDataError:FitnessDataError
          ]
   Which: at location [1] is FitnessDataError:<FitnessDataError> instead of FitnessDataLoaded:<FitnessDataLoaded>

Am I doing anything wrong here? I'm just starting to learn about tests so any help would be appreciated! Thank you!

bloc_test question

Most helpful comment

Hi @henryla92 馃憢
Thanks for opening an issue!

I鈥檓 guessing it鈥檚 because your test seems highly dependent on DateTime.now() which causes it to be flaky. I would try changing your stub to use any rather than DateTime.now() like:

when(mockFitnessDataAuthenticationRepository.getSteps(any, any)).thenAnswer((_) => Future.value(tst));

Let me know if that helps!

If you can share a link to the repo I鈥檓 more than happy to take a closer look and open a PR with suggestions 馃憤

That solved it! Thank you so much. 馃檹馃檹

I didn't expect the DateTime.now() to be the culprit haha 馃し

All 3 comments

Hi @henryla92 馃憢
Thanks for opening an issue!

I鈥檓 guessing it鈥檚 because your test seems highly dependent on DateTime.now() which causes it to be flaky. I would try changing your stub to use any rather than DateTime.now() like:

when(mockFitnessDataAuthenticationRepository.getSteps(any, any)).thenAnswer((_) => Future.value(tst));

Let me know if that helps!

If you can share a link to the repo I鈥檓 more than happy to take a closer look and open a PR with suggestions 馃憤

Closing for now but feel free to comment with additional questions and I'm happy to continue the conversation 馃憤

Hi @henryla92 馃憢
Thanks for opening an issue!

I鈥檓 guessing it鈥檚 because your test seems highly dependent on DateTime.now() which causes it to be flaky. I would try changing your stub to use any rather than DateTime.now() like:

when(mockFitnessDataAuthenticationRepository.getSteps(any, any)).thenAnswer((_) => Future.value(tst));

Let me know if that helps!

If you can share a link to the repo I鈥檓 more than happy to take a closer look and open a PR with suggestions 馃憤

That solved it! Thank you so much. 馃檹馃檹

I didn't expect the DateTime.now() to be the culprit haha 馃し

Was this page helpful?
0 / 5 - 0 ratings