Модульное тестирование Dart, Flutter Redux Thunk

Я написал следующий код и пытаюсь протестировать действие редуктора во флаттере. К сожалению, когда я отлаживаю код, я вижу, что thunkMiddleware не перехватывает действие, как ожидалось (поскольку возвращаемый Function(store) никогда не запускается).

state.dart

@JsonSerialize()
class Pokemon {
  final String name;
  final String url;

  Pokemon(this.name, this.url);

  factory Pokemon.fromJson(Map<String, dynamic> json) =>
      _$PokemonFromJson(json);
}

// state
@immutable
class PokemonsState {
  final List<Pokemon> pokemons;
  final bool isLoading;
  final Exception ex;

  const PokemonsState(
      {this.pokemons = const [], this.isLoading = false, this.ex});

  PokemonsState copyWith(
      {List<Pokemon> pokemons, bool isLoading, Exception ex}) {
    return PokemonsState(
        pokemons: pokemons ?? this.pokemons,
        isLoading: isLoading ?? this.isLoading,
        ex: ex ?? this.ex);
  }
}

// reducer
PokemonsState pokemonsState(PokemonsState state, action) {
  switch (action.runtimeType) {
    case FetchPokemons:
      return state.copyWith(isLoading: true);
    case AddPokemons:
      if (action.error == null)
        return state.copyWith(
            pokemons: action.payload, isLoading: false, ex: null);

      return state.copyWith(ex: action.error, isLoading: false);
  }
  return state;
}

// actions
class FetchPokemons {}

class AddPokemons {
  final List<Pokemon> payload;
  final Exception error;

  AddPokemons({this.payload, this.error});
}

// thunks
loadPokemons(Client client) {
  return (Store<AppState> store) async {
    store.dispatch(FetchPokemons());
    try {
      var res = await client.get(pokemonUrl);
      if (res.statusCode == HttpStatus.ok) {
        final pokemons = jsonDecode(res.body)['results'];
        store.dispatch(AddPokemons(
            payload:
                List<Pokemon>.from(pokemons.map((i) => Pokemon.fromJson(i)))));
      } else {
        throw HttpException(res.reasonPhrase);
      }
    } on Exception catch (e) {
      store.dispatch(AddPokemons(error: e));
    }
  };
}


state_test.dart

class MockClient extends Mock implements Client{}

void main(){

    Store<PokemonsState> store;

    setUp(() {
      store = Store(pokemonsState,
          initialState: PokemonsState(), middleware: [thunkMiddleware]);
    });

    test('add Pokemons success should add a list of pokemons to the store',
            () {
          final client = MockClient();

          when(client.get(argThat(isInstanceOf<String>()))).thenAnswer((_) async =>
              Response(
                  '{"results": [{"name": "p1", "url": "u1"}, {"name": "p2", "url": "u2"}]}',
                  200));

          store.dispatch(loadPokemons(client));
          expect(store.state.pokemons.length, 2);
        });
      });

}

Будем признательны за любую помощь в исправлении теста!


person aprofromindia    schedule 17.09.2019    source источник


Ответы (1)


Я столкнулся с той же проблемой. Вот мое решение:

void main() {
  Store<AppState> store;

  setUp(() {
    store = Store(
      appStateReducer,
      initialState: AppState.initialState(),
      middleware: [thunkMiddleware],
    );
  });

  test('', () async {
    await store.dispatch(fetchLocalization());
    expect(store.state.localization.get('WELCOME'), 'Welcome');
  });
}

Я создал пользовательский appStateReducer, который привязан к действиям, которые не делают никаких HTTP-вызовов.

Вот:

class SetLocalization {
  final Map<String, String> values;
  SetLocalization(this.values);
}

ThunkAction<AppState> fetchLocalization() {
  return (Store<AppState> store) async {
    var localization = await _LocalizationApi().read();
    store.dispatch(SetLocalization(localization));
  };
}

// used to fake http call
class _LocalizationApi {
  final Map<String, String> data = {
    'WELCOME': 'WECLOME',
    'WELCOME_MESSAGE': 'Welcome'
  };
  Future<Map<String, String>> read() async => data;
}
person Olivier Picault    schedule 18.04.2020