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

2

8

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); 
  }
}
Handwriting answered 5/5, 2021 at 15:26 Comment(0)
L
6

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.

Lechery answered 5/5, 2021 at 17:48 Comment(5)
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.Handwriting
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]; ```Lechery
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; Handwriting
@Naddle did you find the solution? Im getting the same message.Edgy
@PaulPérez unfortunately, I did not.Handwriting
D
6

As mentioned above you can use the isA, matcher. To check the properties, try using the having method available in this matcher.

 expect: () => [isA<WeatherLoaded>()..having((p0) => p0.temprature, "description", "30")];

Here "30" is the expected value.

Like this, you can check all the properties.

Declamation answered 10/8, 2022 at 9:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.