Search code examples
flutterstate-managementbloc-test

How can I test a future function using bloc test


I'm new to bloc and currently learning bloc testing. The below code is working fine in debug mode. However, I can't find anything to await the function to test the current position/error. Here is my bloc

  class GoogleMapBloc extends Bloc<GoogleMapEvent, GoogleMapState> {
  GoogleMapBloc() : super(const GoogleMapState()) {
    on<CurrentLocationEvent>(_showCurrentPosition);
  }

  //This is the bloc logic

  void _showCurrentPosition(
      CurrentLocationEvent event, Emitter<GoogleMapState> emit) async {
    try {
      emit(state.copyWith(loadStatus: LoadStatus.loading));
      Position position = await _getCurrentLocation();
      final Marker marker = Marker(
        markerId: const MarkerId('current_position'),
        position: LatLng(position.latitude, position.longitude),
      );
      Set<Marker> markers = {};
      markers.add(marker);
      emit(state.copyWith(
          loadStatus: LoadStatus.success,
          currentPosition: position,
          markers: markers));
    } catch (e) {
      //debugPrint("Exception ===> ${e.toString()}");
      emit(state.copyWith(
          loadStatus: LoadStatus.fail,
          markers: {},
          error: e.toString().substring(11)));
    }
  }
  
  //This will fetch current user or error
  Future<Position> _getCurrentLocation() async {
    bool serviceEnabled;
    LocationPermission permission;

    // Test if location services are enabled.
    serviceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serviceEnabled) {
      // Location services are not enabled don't continue
      // accessing the position and request users of the
      // App to enable the location services.
      throw Exception('Location services are disabled.');
    }

    permission = await Geolocator.checkPermission();
    if (permission == LocationPermission.denied) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        // Permissions are denied, next time you could try
        // requesting permissions again (this is also where
        // Android's shouldShowRequestPermissionRationale
        // returned true. According to Android guidelines
        // your App should show an explanatory UI now.
        throw Exception('Location permissions are denied');
      }
    }

    if (permission == LocationPermission.deniedForever) {
      // Permissions are denied forever, handle appropriately.
      throw Exception(
          'Location permissions are permanently denied, we cannot request permissions.');
    }
    // When we reach here, permissions are granted and we can
    // continue accessing the position of the device.
    return await Geolocator.getCurrentPosition();
  }
}
             

Here, I'm confused, as to how can I await the function without using the wait as this is an async call.

    void googleMapBloc() {
  group("Google Map Bloc Testing", () {
    blocTest<GoogleMapBloc, GoogleMapState>(
      'Check location enabled',
      build: () => GoogleMapBloc(),
      act: (bloc) => bloc.add(const CurrentLocationEvent()),
      wait: const Duration(milliseconds: 10000),
      expect: () => <GoogleMapState>[
        const GoogleMapState(loadStatus: LoadStatus.loading),
        const GoogleMapState(
            markers: {}, loadStatus: LoadStatus.fail, error: ""),
      ],
    );
  });
} 

Also, how can I mock this for the api request


Solution

  • You have to use wait for async function in bloc test. Set the wait time in bloc test w.r.t your assumption in how much time your async function will get executed. e.g.

    Assume the function _getCurrentLocation() takes 5 secs to execute. Just wait for 5 secs in bloc test like wait: const Duration(milliseconds: 5000) in your bloc test function. Also make sure you extend your blocstate with equatable like GoogleMapState extends Equatable.