测试/模拟flutter中的文件IO



我有一个简单的测试:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
Future<void> main() async {
testWidgets(
'Simple empty test',
(WidgetTester tester) async {
print("1");
await Directory('/tmp').exists();
print("2");
await tester.pumpWidget(Container());
},
);
}

打印1后冻结。我知道Flutter在伪异步区域中运行测试,我知道我需要用runAsync运行带有真实IO的代码。

但是,是否也可以以某种方式注入一个模拟IO文件系统并在不运行Async的情况下运行测试?

经过一些研究,我发现了来自谷歌团队的file包,它允许开发人员使用LocalFileSystem(基本上是dart:io(、MemoryFileSystem或自定义FileSystem

特别是MemoryFileSystem,甚至自定义FileSystem,对于单元和小部件测试都很有用,因为它们可以使用,所以不会在硬盘上创建文件。因此,在测试运行后创建和清理FileSystem要容易得多。

这种方法的缺点是必须将FileSystem注入到每个需要访问文件目录等的模块中。

示例

import 'package:file/file.dart';
class DirectoryOperator {
final FileSystem fileSystem;
// Inject implementation of the FileSystem
DirectoryOperator({required this.fileSystem});
Future<void> methodOperatingOnFileSystem(String path) async {
Directory directory = fileSystem.directory(path);
await directory.create(recursive: true);
}
}

测试代码

import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_test/flutter_test.dart';
main() {
test('$DirectoryOperator creates directory on path', () async {
FileSystem fileSystem = MemoryFileSystem();
var systemUnderTest = DirectoryOperator(fileSystem: fileSystem);
String testPath = 'Path/to/dir';
await systemUnderTest.methodOperatingOnFileSystem(testPath);
bool doesDirectoryExist = await fileSystem.directory(testPath).exists();
expect(
doesDirectoryExist,
isTrue,
);
});
}

I/O操作可以使用mockito和IOOverrides:进行模拟

import 'dart:io';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
import 'test.mocks.dart';
class TestFile extends MockFile {
final String _path;
TestFile(this._path) {
when(readAsStringSync()).thenReturn('(string from $_path)');
}
}
@GenerateMocks([File])
void main() {
test('I/O overrides', () {
IOOverrides.runZoned(() {
expect(File('path/to/a').readAsStringSync(), '(string from path/to/a)');
expect(File('path/to/b').readAsStringSync(), '(string from path/to/b)');
}, createFile: (String path) => TestFile(path));
});
}

上面的示例使用IOOverrides挂接创建File对象,并返回一个类似于模拟File的对象。

最新更新