Regards, dear @felangel
I have a doubt, when trying to implement the test of a particular Bloc that only allows me to know if the user's device has connectivity or not:
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:connectivity/connectivity.dart';
enum ConnectivityEvent {
disable,
enable,
}
class ConnectivityBloc extends Bloc<ConnectivityEvent, bool> {
StreamSubscription _connectivitySubscription;
ConnectivityBloc() {
_connectivitySubscription = Connectivity().onConnectivityChanged.listen(
(ConnectivityResult result) {
if (result == ConnectivityResult.none) {
add(ConnectivityEvent.disable);
} else {
add(ConnectivityEvent.enable);
}
},
);
}
@override
bool get initialState => false;
@override
Stream<bool> mapEventToState(ConnectivityEvent event) async* {
switch (event) {
case ConnectivityEvent.disable:
yield false;
break;
case ConnectivityEvent.enable:
yield true;
break;
}
}
@override
Future<void> close() {
_connectivitySubscription.cancel();
return super.close();
}
}
Using the following unit test:
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/blocs/blocs.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('ConnectivityBloc', () {
ConnectivityBloc connectivityBloc;
setUp(() {
connectivityBloc = ConnectivityBloc();
});
blocTest(
'initial state is false',
build: () => connectivityBloc,
expect: [false],
);
blocTest(
'state should be true on connection enable',
build: () => connectivityBloc,
act: (bloc) => bloc.add(ConnectivityEvent.enable),
expect: [false, true],
);
});
}
The console prints out the next message everytime a blocTest is make it:
โโโก EXCEPTION CAUGHT BY SERVICES LIBRARY โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The following MissingPluginException was thrown while activating platform stream on channel
plugins.flutter.io/connectivity_status:
MissingPluginException(No implementation found for method listen on channel
plugins.flutter.io/connectivity_status)
When the exception was thrown, this was the stack:
#0 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:319:7)
<asynchronous suspension>
#1 EventChannel.receiveBroadcastStream.<anonymous closure> (package:flutter/src/services/platform_channel.dart:517:29)
#3 EventChannel.receiveBroadcastStream.<anonymous closure> (package:flutter/src/services/platform_channel.dart:503:64)
#14 new ConnectivityBloc (package:uba_app/blocs/connectivity/connectivity_bloc.dart:21:70)
#15 main.<anonymous closure>.<anonymous closure> (file:///C:/Apps/uba_app/test/blocs/connectivity_bloc_test.dart:11:26)
#16 Declarer._runSetUps.<anonymous closure> (package:test_api/src/backend/declarer.dart:294:51)
#28 Declarer._runSetUps (package:test_api/src/backend/declarer.dart:294:18)
#41 Declarer._runSetUps (package:test_api/src/backend/declarer.dart)
(elided 52 frames from package dart:async, package dart:async-patch, and package stack_trace)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
00:21 +2: All tests passed!
I think I understand the reason for this exception, after all the connectivity package is not available for native Dart and my OS (Windows) can't register it; only for Flutter [Android | iOS].
Is it possible to do the Bloc unit test without having to receive this exception messages?
My project info:
Hello ๐
Connectivity depends on the native platform to access the network state and this is not possible inside a widget test.
Try mocking the instance of Connectivity with mockito.
Thanks @ResoDev!
When applying your advice of trying to use mockito the exception stopped appearing, as a record, I leave here what I applied:
connectivity_bloc.dart
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:connectivity/connectivity.dart';
import 'package:meta/meta.dart';
enum ConnectivityEvent {
disable,
enable,
}
class ConnectivityBloc extends Bloc<ConnectivityEvent, bool> {
final Stream<ConnectivityResult> connectivityStream;
StreamSubscription _connectivitySubscription;
ConnectivityBloc({
@required this.connectivityStream,
}) {
_connectivitySubscription = connectivityStream.listen(
(ConnectivityResult result) {
if (result == ConnectivityResult.none) {
add(ConnectivityEvent.disable);
} else {
add(ConnectivityEvent.enable);
}
},
);
}
@override
bool get initialState => false;
@override
Stream<bool> mapEventToState(ConnectivityEvent event) async* {
switch (event) {
case ConnectivityEvent.disable:
yield false;
break;
case ConnectivityEvent.enable:
yield true;
break;
}
}
@override
Future<void> close() {
_connectivitySubscription.cancel();
return super.close();
}
}
connectivity_bloc_test.dart
import 'package:bloc_test/bloc_test.dart';
import 'package:connectivity/connectivity.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:my_app/blocs/blocs.dart';
class MockConnectivity extends Mock implements Connectivity {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('ConnectivityBloc', () {
Connectivity connectivity;
Stream<ConnectivityResult> connectivityStream;
ConnectivityBloc connectivityBloc;
setUp(() {
connectivity = MockConnectivity();
when(connectivity.onConnectivityChanged).thenAnswer((_) {
return Stream.value(ConnectivityResult.none);
});
connectivityStream = connectivity.onConnectivityChanged;
connectivityBloc = ConnectivityBloc(connectivityStream: connectivityStream);
});
blocTest(
'initial state is false',
build: () => connectivityBloc,
expect: [false],
);
blocTest(
'state should be true on connection enable',
build: () => connectivityBloc,
act: (bloc) => bloc.add(ConnectivityEvent.enable),
expect: [false, true],
);
});
}
Console output
$ flutter test
00:06 +2: All tests passed!
Most helpful comment
Thanks @ResoDev!
When applying your advice of trying to use
mockitothe exception stopped appearing, as a record, I leave here what I applied:connectivity_bloc.dart
connectivity_bloc_test.dart
Console output