Created
October 15, 2019 08:07
-
-
Save brianegan/9e1a8711ad35b7d1b3e81c967d2669e1 to your computer and use it in GitHub Desktop.
An example of how to test bloc streams and ideas to make it simpler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'dart:async'; | |
| import 'package:bloc/bloc.dart'; | |
| import 'package:mockito/mockito.dart'; | |
| import 'package:test/test.dart'; | |
| enum CounterEvent { increment, decrement } | |
| class CounterBloc extends Bloc<CounterEvent, int> { | |
| @override | |
| int get initialState => 0; | |
| @override | |
| Stream<int> mapEventToState(CounterEvent event) async* { | |
| switch (event) { | |
| case CounterEvent.increment: | |
| yield state + 1; | |
| break; | |
| case CounterEvent.decrement: | |
| yield state - 1; | |
| break; | |
| } | |
| } | |
| } | |
| class MockBloc<State> extends Mock { | |
| Stream<State> get mockState; | |
| StreamSubscription<State> listen( | |
| void onData(State value), { | |
| Function onError, | |
| void onDone(), | |
| bool cancelOnError, | |
| }) { | |
| return mockState.listen( | |
| onData, | |
| onError: onError, | |
| onDone: onDone, | |
| cancelOnError: cancelOnError, | |
| ); | |
| } | |
| } | |
| class RawMockCounterBloc extends Mock implements CounterBloc {} | |
| class MockCounterBloc extends MockBloc<int> implements CounterBloc {} | |
| void main() { | |
| group('CounterBloc', () { | |
| test('starts with 0', () { | |
| expect(CounterBloc().state, 0); | |
| }); | |
| test('increments by 1', () { | |
| final bloc = CounterBloc()..add(CounterEvent.increment); | |
| expect(bloc, emitsInOrder([0, 1])); | |
| }); | |
| test('decrements by 1', () { | |
| final bloc = CounterBloc()..add(CounterEvent.decrement); | |
| expect(bloc, emitsInOrder([0, -1])); | |
| }); | |
| test('can mock the stream', () { | |
| final mockBloc = RawMockCounterBloc(); | |
| when(mockBloc.listen(any, | |
| onError: anyNamed('onError'), | |
| onDone: anyNamed('onDone'), | |
| cancelOnError: anyNamed('cancelOnError'))) | |
| .thenAnswer((Invocation invocation) { | |
| return Stream.fromIterable([1, 2, 3]).listen( | |
| invocation.positionalArguments.first, | |
| onError: invocation.namedArguments['onError'], | |
| onDone: invocation.namedArguments['onDone'], | |
| cancelOnError: invocation.namedArguments['cancelOnError'], | |
| ); | |
| }); | |
| expect(mockBloc, emitsInOrder([1, 2, 3])); | |
| }); | |
| test('can mock the stream with a helper', () { | |
| final mockBloc = RawMockCounterBloc(); | |
| whenListen(mockBloc, Stream.fromIterable([1, 2, 3])); | |
| expect(mockBloc, emitsInOrder([1, 2, 3])); | |
| }); | |
| test('can mock the stream with an exteded class', () { | |
| final mockBloc = MockCounterBloc(); | |
| when(mockBloc.mockState) | |
| .thenAnswer((_) => Stream.fromIterable([1, 2, 3])); | |
| expect(mockBloc, emitsInOrder([1, 2, 3])); | |
| }); | |
| }); | |
| } | |
| void whenListen<Event, State>( | |
| Bloc<Event, State> bloc, | |
| Stream<State> stream, | |
| ) { | |
| when(bloc.listen(any, | |
| onError: anyNamed('onError'), | |
| onDone: anyNamed('onDone'), | |
| cancelOnError: anyNamed('cancelOnError'))) | |
| .thenAnswer((Invocation invocation) { | |
| return stream.listen( | |
| invocation.positionalArguments.first, | |
| onError: invocation.namedArguments['onError'], | |
| onDone: invocation.namedArguments['onDone'], | |
| cancelOnError: invocation.namedArguments['cancelOnError'], | |
| ); | |
| }); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment