Mock getExternalStorageDirectory on Flutter

Viewed 2662

I´m trying mock the function getExternalStorageDirectory, but alway return the error: "UnsupportedError (Unsupported operation: Functionality only available on Android)"

I´m using the method setMockMethodCallHandler to mock it, but the erro occurs before the method be called.

test method

    test('empty listReportModel', () async {
      
      TestWidgetsFlutterBinding.ensureInitialized();
      final directory = await Directory.systemTemp.createTemp();
      const MethodChannel channel =
          MethodChannel('plugins.flutter.io/path_provider');
      channel.setMockMethodCallHandler((MethodCall methodCall) async {
        if (methodCall.method == 'getExternalStorageDirectory') {
          return directory.path;
        }
        return ".";
      });

      when(Modular.get<IDailyGainsController>().listDailyGains())
          .thenAnswer((_) => Future.value(listDailyGainsModel));

      when(Modular.get<IReportsController>().listReports())
          .thenAnswer((_) => Future.value(new List<ReportsModel>()));

      var configurationController = Modular.get<IConfigurationController>();

      var response = await configurationController.createBackup();

      expect(response.filePath, null);
    });

method

  Future<CreateBackupResponse> createBackup() async {
    CreateBackupResponse response = new CreateBackupResponse();

    var dailyGains = await exportDailyGainsToCSV();
    var reports = await exportReportsToCSV();

    final Directory directory = await getApplicationDocumentsDirectory();
    final Directory externalDirectory = await getExternalStorageDirectory();

    if (dailyGains.filePath != null && reports.filePath != null) {
      File dailyGainsFile = File(dailyGains.filePath);
      File reportsFile = File(reports.filePath);

      var encoder = ZipFileEncoder();
      encoder.create(externalDirectory.path + "/" + 'backup.zip');
      encoder.addFile(dailyGainsFile);
      encoder.addFile(reportsFile);
      encoder.close();

      await _removeFile(dailyGainsFile.path);
      await _removeFile(reportsFile.path);

      response.filePath = directory.path + "/" + 'backup.zip';
    }

    return response;
  }
1 Answers

As in pub.dev stated:

path_provider now uses a PlatformInterface, meaning that not all platforms share the a single PlatformChannel-based implementation. With that change, tests should be updated to mock PathProviderPlatform rather than PlatformChannel.

That means somewhere in your test directory you create the following mock class:

import 'package:mockito/mockito.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';

const String kTemporaryPath = 'temporaryPath';
const String kApplicationSupportPath = 'applicationSupportPath';
const String kDownloadsPath = 'downloadsPath';
const String kLibraryPath = 'libraryPath';
const String kApplicationDocumentsPath = 'applicationDocumentsPath';
const String kExternalCachePath = 'externalCachePath';
const String kExternalStoragePath = 'externalStoragePath';

class MockPathProviderPlatform extends Mock
    with MockPlatformInterfaceMixin
    implements PathProviderPlatform {
  Future<String> getTemporaryPath() async {
    return kTemporaryPath;
  }

  Future<String> getApplicationSupportPath() async {
    return kApplicationSupportPath;
  }

  Future<String> getLibraryPath() async {
    return kLibraryPath;
  }

  Future<String> getApplicationDocumentsPath() async {
    return kApplicationDocumentsPath;
  }

  Future<String> getExternalStoragePath() async {
    return kExternalStoragePath;
  }

  Future<List<String>> getExternalCachePaths() async {
    return <String>[kExternalCachePath];
  }

  Future<List<String>> getExternalStoragePaths({
    StorageDirectory type,
  }) async {
    return <String>[kExternalStoragePath];
  }

  Future<String> getDownloadsPath() async {
    return kDownloadsPath;
  }
}

And build your tests the following way:

void main() {
  group('PathProvider', () {
    TestWidgetsFlutterBinding.ensureInitialized();

    setUp(() async {
      PathProviderPlatform.instance = MockPathProviderPlatform();
      // This is required because we manually register the Linux path provider when on the Linux platform.
      // Will be removed when automatic registration of dart plugins is implemented.
      // See this issue https://github.com/flutter/flutter/issues/52267 for details
      disablePathProviderPlatformOverride = true;
    });

    test('getTemporaryDirectory', () async {
      Directory result = await getTemporaryDirectory();
      expect(result.path, kTemporaryPath);
    });
  } 
}

Here you can check out the complete example.

Related