Write a test for reading and writing files in dart

283

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);
  });
}```
Share:
283
El_Loco
Author by

El_Loco

PhD-student in Computer Vision who wants to learn more math!

Updated on December 01, 2022

Comments

  • El_Loco
    El_Loco over 1 year

    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.

    • jamesdlin
      jamesdlin about 2 years
      Did you follow the instructions from the error message and try calling WidgetsFlutterBinding.ensureInitialized() first?
    • El_Loco
      El_Loco about 2 years
      I think it should be a Widget test instead of Unit test