I am learning Flutter and Dart currently. Now I want to read and write files to memory. I have code for reading and writing. Now I want tests for that. Here is where I run into problems. I always get:
'package:flutter/src/services/platform_channel.dart': Failed assertion: line 134 pos 7: '_binaryMessenger != null || ServicesBinding.instance != null': Cannot use this MethodChannel before the binary messenger has been initialized. This happens when you invoke platform methods before the WidgetsFlutterBinding has been initialized. You can fix this by either calling WidgetsFlutterBinding.ensureInitialized() before this or by passing a custom BinaryMessenger instance to MethodChannel().
dart:core _AssertionError._throwNew
package:flutter/src/services/platform_channel.dart 134:7 MethodChannel.binaryMessenger
package:flutter/src/services/platform_channel.dart 167:36 MethodChannel._invokeMethod
package:flutter/src/services/platform_channel.dart 350:12 MethodChannel.invokeMethod
package:path_provider_macos/path_provider_macos.dart 48:10 PathProviderMacOS.getApplicationDocumentsPath
package:path_provider/path_provider.dart 115:40 getApplicationDocumentsDirectory
package:skeet25pro/main_counter.dart 18:29 CounterStorage._localPath
package:skeet25pro/main_counter.dart 24:24 CounterStorage._localFile
package:skeet25pro/main_counter.dart 43:24 CounterStorage.writeCounter
test/file_io_test.dart 8:27 main.<fn>
test/file_io_test.dart 5:33 main.<fn>
main_counter.dart
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(
MaterialApp(
title: 'Reading and Writing Files',
home: FlutterDemo(storage: CounterStorage()),
),
);
}
class CounterStorage {
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/counter.txt');
}
Future<int> readCounter() async {
try {
final file = await _localFile;
// Read the file
final contents = await file.readAsString();
return int.parse(contents);
} catch (e) {
// If encountering an error, return 0
return 0;
}
}
Future<File> writeCounter(int counter) async {
final file = await _localFile;
// Write the file
return file.writeAsString('$counter');
}
}
class FlutterDemo extends StatefulWidget {
const FlutterDemo({Key? key, required this.storage}) : super(key: key);
final CounterStorage storage;
@override
_FlutterDemoState createState() => _FlutterDemoState();
}
class _FlutterDemoState extends State<FlutterDemo> {
int _counter = 0;
@override
void initState() {
super.initState();
widget.storage.readCounter().then((int value) {
setState(() {
_counter = value;
});
});
}
Future<File> _incrementCounter() {
setState(() {
_counter++;
});
// Write the variable as a string to the file.
return widget.storage.writeCounter(_counter);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Reading and Writing Files'),
),
body: Center(
child: Text(
'Button tapped $_counter time${_counter == 1 ? '' : 's'}.',
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
file_io_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:skeet25pro/main_counter.dart';
void main() {
test('Check file save works', () async {
final CounterStorage storage = CounterStorage();
var counter = 6;
var t = await storage.writeCounter(counter);
expect(1, 1);
});
}
When I run the app through a simulator, it works perfectly fine. I would really like to get the tests running.
EDIT: If I try and add WidgetsFlutterBinding.ensureInitialized();
void main() {
test('Check file save works', () async {
WidgetsFlutterBinding.ensureInitialized();
final CounterStorage storage = CounterStorage();
var counter = 6;
var t = await storage.writeCounter(counter);
expect(1, 1);
});
}
I get the error:
MissingPluginException(No implementation found for method getApplicationDocumentsDirectory on channel plugins.flutter.io/path_provider_macos)
package:flutter/src/services/platform_channel.dart 175:7 MethodChannel._invokeMethod
Seems like one should use something like: setMockMethodCallHandler
to intercept the call to the different directory providers. Still no working solution.
You have to mock the path_provider call and maybe put the WidgetsFlutterBinding.ensureInitialized();
at the beginning of main. I guess you want something like
Future<void> main() async {
TestWidgetsFlutterBinding.ensureInitialized();
setUpAll(() {
const channel = MethodChannel(
'plugins.flutter.io/path_provider_macos',
);
channel.setMockMethodCallHandler((MethodCall methodCall) async {
switch (methodCall.method) {
case 'getApplicationDocumentsDirectory':
return "PATH_TO_MOCK_DIR";
default:
}
});
});
test('Check file save works', () async {
final CounterStorage storage = CounterStorage();
var counter = 6;
var t = await storage.writeCounter(counter);
expect(1, 1);
});
}```