简体   繁体   中英

How I can enforce in-memory file io during testing?

I am making a class for saving some user-provided settings to my application:

import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as p;

class UserSettings
{
   late final String _path;
   UserSettings(){
      String os = Platform.operatingSystem;
      String home = "";
      Map<String, String> envVars = Platform.environment;
      if (Platform.isMacOS || Platform.isLinux) {
        home = envVars['HOME'] as String;
      } else if (Platform.isWindows) {
        home = envVars['UserProfile'] as String;
      }

      _path = p.join(home, ".settings.json");
   }

   Future<Map<String, dynamic>> readSettings(File? settingFile) {
   
       if (settingFile == null) {
        settingsFile = File(_path);
      }

      if (!settingsFile.exists()) {
        return new Map<String, dynamic>();
      }

      String json = settingsFile.readAsString();
      Map<String, dynamic> settings = Map.castFrom(json.decode(json));

      return settings;
   }

   Future<Map<String, dynamic>> writeSettings(Strikg key, dynamic value) {
      File settingsFile = File(_path);
      Map<String,dynamic> settings = await readSettings();

      settings[key] = value;
      await settingsFile.writeAsString(json.encode(jsonData));
   }
}

And I want to test whether class is able to read and write the file correctly:


test('Test that accesstoken and Store is is written', () async {
    UserSettings settings = UserSettings();
    
    settings.writeSettings('mytoken','somevalue');
    settings.saveStoreId('myid',522);

    Map<String,dynamic> settings = settings.readSettings(null);

    assert(settings['store_id']==522,'Is is not saved');
    assert(settings['mytoken']=='somevalue','Token is not saved');
});

But as you can see I need to access the home folder. Is there some way to mock the path with some in-memory one and emulate both cases that are windows or linux?

Use package:file . Any function that currently constructs File or Directory objects would need to be changed to take a FileSystem argument and instead would need to call methods on that ( FileSystem.file or FileSystem.directory ) to construct equivalent objects. Typically such FileSystem arguments can be optional and can default to const LocalFileSystem() . Note that functions that operate on File or Directory objects do not need to be changed since package:file provides File and Directory classes that have the same names and that implement the same interfaces as their dart:io counterparts.

Tests then can create a MemoryFileSystem , set it up fake, in-memory files and directories, and pass that to your functions instead.

The typical way you'd enforce using package:file 's File and Directory classes instead of dart:io 's is to import dart:io only with a prefix:

import 'dart:io' as io;

to force its use to be explicit. If adding io. prefixes throughout your code is too onerous, you alternatively can hide any conflicting classes. For example:

import 'dart:io' hide File, Directory;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM