Dart / Flutter test cubit, problem with comparing expected and actual

1,221

You can use the isA matcher if you are trying to test the type.

expect: () => [isA<WeatherLoaded>()];

If you are trying to compare the values of the returned object you need to either use the Equatable package, or manually override the hashCode and == operator in your Cubit.

Share:
1,221
CoffeeToCodette
Author by

CoffeeToCodette

Updated on December 01, 2022

Comments

  • CoffeeToCodette
    CoffeeToCodette over 1 year

    I'm working on an app using a WeatherAPI. I currently fail to implement some working tests. I tried to follow ResoCoders Guide (https://resocoder.com/2019/11/29/bloc-test-tutorial-easier-way-to-test-blocs-in-dart-flutter/) and actually implemented all states, blocs (I used Cubit instead), classes, functions, ... almost the same.

    This is my test's code:

    blocTest<WeatherCubit, WeatherBaseState>(
          'Cubit emits WeatherLoaded',
          build: () {
            return WeatherCubit(weatherRepository: mockWeatherRepository);
          },
          act: (WeatherCubit cubit) => cubit.getWeather(),
          expect: () => [
            WeatherLoaded(
                temperature: temperature,
                ...
                lat: lat,
                lon: lon)
          ],
        );
    

    And that's my error massage from the debug console:

    Expected: [Instance of 'WeatherLoaded']
      Actual: [Instance of 'WeatherLoaded']
       Which: at location [0] is <Instance of 'WeatherLoaded'> instead of <Instance of 'WeatherLoaded'>
    
    WARNING: Please ensure state instances extend Equatable, override == and hashCode, or implement Comparable.
    Alternatively, consider using Matchers in the expect of the blocTest rather than concrete state instances.
    

    I tried to use a Matcher but did not quite get how to use it.

    In case the problem lies here, my implementation of the WeatherCubit:

    class WeatherCubit extends Cubit<WeatherBaseState> {
      final IWeatherRepository weatherRepository; //IWeatherRepository is interface
    
      WeatherCubit({required this.weatherRepository})
          : super(LoadingWeather()); // I use LoadingWeather as initial state
    
    
      Future<void> getWeather() async {
        final Position location = await weatherRepository.determinePosition();
        final WeatherData data = await weatherRepository.getWeather(
            lat: location.latitude, 
            lon: location.longitude); 
        final WeatherLoaded weatherLoaded = WeatherLoaded(
            temperature: data.temperature,
            ...
            lat: data.lat, 
            lon: data.lon); 
        emit(weatherLoaded); 
      }
    }
    
  • CoffeeToCodette
    CoffeeToCodette about 3 years
    Thank you! Actually, WeatherLoaded implements Equatable like in the ResoCoder example. What do I have to change though? I wanted to test if the State is created correctly.
  • edgeboy7
    edgeboy7 about 3 years
    When you extend Equatable, you have to override the props getter and place all the class variables in the list. ``` @override List<Object> get props => [latitude, longitude, temperature]; ```
  • CoffeeToCodette
    CoffeeToCodette about 3 years
    It gets autogenerated by Equatable so I already have that. That can't be the problem. @override List<Object?> get props => [ lat, lon, temperature, ... ]; @override bool? get stringify => true;
  • Paul Pérez
    Paul Pérez over 2 years
    @Naddle did you find the solution? Im getting the same message.
  • CoffeeToCodette
    CoffeeToCodette over 2 years
    @PaulPérez unfortunately, I did not.