-
-
Notifications
You must be signed in to change notification settings - Fork 622
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Really hate static methods... #722
Comments
@jaumard I admit this might not have been the best choice I have made. However in my defence common practise on testing and application architecture in general suggests that you should not mock what you don't own (more reading here). My suggestion would be to write a wrapper around the geolocator and mock the wrapper instead. |
Your link is more about TDD than unit testing in general. Also if we don't mock it the test don't pass I suppose because there is no implementation on it when running test. Also I want to check that geolocation is called in my code and check what I do with the result is correct. So many reason you want to mock third party deps :) Also don't mock deps using network and run your tests with no network, it will be fun :D or even with really show network and get 1 hour to execute your tests lol But yeah I'll do my own wrapper around geolocator, just wondering if something was built in before doing it. |
The link also suggests to create wrappers/ adapters/ shims for thirds party dependencies and mock those instead, for the specific reasons you mentioned. This way your are mocking only code that you own (as in you are the owner of the wrappers/ adapters/ shims). This has the following benefits:
I will close this issue, but feel free to continue the discussion ;) |
I think that this class could be useful to wrap the static methods and next mock it. import 'dart:async';
import 'package:geolocator/geolocator.dart';
class GeolocatorWrapper {
StreamController<Position>? _positionController;
StreamController<bool>? _serviceEnabledController;
StreamSubscription? _positionSubscription, _serviceEnabledSubscription;
/// check if the Location Service is Enabled
Future<bool> get isLocationServiceEnabled => Geolocator.isLocationServiceEnabled();
/// Returns a [Future] indicating if the user allows the App to access the device's location.
Future<LocationPermission> checkPermission() => Geolocator.checkPermission();
Future<bool> get hasPermission async {
final status = await checkPermission();
return status == LocationPermission.always || status == LocationPermission.whileInUse;
}
/// Calculates the initial bearing between two points
double bearing(
double startLatitude,
double startLongitude,
double endLatitude,
double endLongitude,
) =>
Geolocator.bearingBetween(
startLatitude,
startLongitude,
endLatitude,
endLongitude,
);
/// return an stream to listen the changes in the GPS status
Stream<bool> get onServiceEnabled {
_serviceEnabledController ??= StreamController.broadcast();
// listen the changes in GPS status
_serviceEnabledSubscription = Geolocator.getServiceStatusStream().listen(
(event) {
final enabled = event == ServiceStatus.enabled;
if (enabled) {
_notifyServiceEnabled(true);
if (_positionController != null) {
_initLocationUpdates();
}
}
},
);
return _serviceEnabledController!.stream;
}
/// return an stream to listen the changes in the current position
Stream<Position> get onLocationUpdates {
_positionController ??= StreamController.broadcast();
_initLocationUpdates();
return _positionController!.stream;
}
/// start listening the position changes
void _initLocationUpdates() async {
await _positionSubscription?.cancel();
_positionSubscription = Geolocator.getPositionStream().listen(
(event) {
_positionController?.sink.add(event);
},
onError: (e) {
if (e is LocationServiceDisabledException) {
_notifyServiceEnabled(false);
}
},
);
}
/// notify to all listeners that the location service has changed
void _notifyServiceEnabled(bool enabled) {
if (_serviceEnabledController != null) {
_serviceEnabledController!.sink.add(enabled);
}
}
Future<bool> openAppSettings() => Geolocator.openAppSettings();
Future<LocationPermission> requestPermission() => Geolocator.requestPermission();
Future<bool> openLocationSettings() => Geolocator.openLocationSettings();
/// returns the current position
Future<Position?> getCurrentPosition({
LocationAccuracy desiredAccuracy = LocationAccuracy.best,
bool forceAndroidLocationManager = false,
Duration? timeLimit,
}) async {
try {
// getCurrentPosition throws an exception when the location service are disabled
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: desiredAccuracy,
forceAndroidLocationManager: forceAndroidLocationManager,
timeLimit: timeLimit,
);
return position;
} catch (e) {
return null;
}
}
/// Returns the last known position stored on the users device.
Future<Position?> getLastKnowPosition({bool forceAndroidLocationManager = false}) async {
return Geolocator.getLastKnownPosition(
forceAndroidLocationManager: forceAndroidLocationManager,
);
}
/// release the controllers and cancel all subscribers
void dispose() {
_positionController?.close();
_serviceEnabledSubscription?.cancel();
_serviceEnabledController?.close();
_positionSubscription?.cancel();
}
}
|
Previous version of the plugin I could instantiate a geolocator, was nice and my unit tests were really happy about it because geolocator could be mocked.
Now everything is static... Is there any new way that doesn't involve static methods ?
The text was updated successfully, but these errors were encountered: