Skip to content

Instantly share code, notes, and snippets.

@brianegan
Created October 15, 2019 08:07
Show Gist options
  • Save brianegan/9e1a8711ad35b7d1b3e81c967d2669e1 to your computer and use it in GitHub Desktop.
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
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