Created
October 15, 2019 08:22
-
-
Save brianegan/26b2ebbb55fed760b89162400cc11fb3 to your computer and use it in GitHub Desktop.
Demonstrates how to test bloc streams
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: captureAnyNamed('onError'), | |
| onDone: captureAnyNamed('onDone'), | |
| cancelOnError: captureAnyNamed('cancelOnError'))) | |
| .thenAnswer((Invocation invocation) { | |
| print(invocation); | |
| return Stream.fromIterable([1, 2, 3]).listen( | |
| invocation.positionalArguments.first, | |
| onError: invocation.namedArguments[Symbol('onError')], | |
| onDone: invocation.namedArguments[Symbol('onDone')], | |
| cancelOnError: invocation.namedArguments[Symbol('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, emitsDone])); | |
| }); | |
| 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: captureAnyNamed('onError'), | |
| onDone: captureAnyNamed('onDone'), | |
| cancelOnError: captureAnyNamed('cancelOnError'))) | |
| .thenAnswer((Invocation invocation) { | |
| return stream.listen( | |
| invocation.positionalArguments.first, | |
| onError: invocation.namedArguments[Symbol('onError')], | |
| onDone: invocation.namedArguments[Symbol('onDone')], | |
| cancelOnError: invocation.namedArguments[Symbol('cancelOnError')], | |
| ); | |
| }); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment