Skip to content

Instantly share code, notes, and snippets.

@brianegan
Created October 15, 2019 08:22
Show Gist options
  • Save brianegan/26b2ebbb55fed760b89162400cc11fb3 to your computer and use it in GitHub Desktop.
Save brianegan/26b2ebbb55fed760b89162400cc11fb3 to your computer and use it in GitHub Desktop.
Demonstrates how to test bloc streams
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