[英]Flutter: readAsBytes/readAsString in widget tests
I am trying to test a StatefulWidget
with the following onPressed
function.我正在尝试使用以下onPressed
函数测试StatefulWidget
。
floatingActionButton: FloatingActionButton(
child: Icon(Icons.camera_alt),
onPressed: () async {
try {
final filename = widget.randomStringGenerator?.call() ?? '';
final path = join(
(await getTemporaryDirectory()).path,
'${filename}.png',
);
await widget.cameraController?.takePicture(path);
final file = File(path);
final image = await file.readAsBytes();
widget.onPhotoTaken(image);
await file.delete();
} catch (e) {
print(e);
}
},
),
and the following widget test:以及以下小部件测试:
void main() {
Directory directory;
group('PhotoWidget test', () {
setUp(() async {
// Create a temporary directory.
directory = await Directory.systemTemp.createTemp();
// Mock out the MethodChannel for the path_provider plugin.
const MethodChannel('plugins.flutter.io/path_provider')
.setMockMethodCallHandler(
(MethodCall methodCall) async {
if (methodCall.method == 'getTemporaryDirectory') {
return directory.path;
}
return null;
},
);
});
tearDown(() async {
await directory?.delete(
recursive: true,
);
});
testWidgets('onPictureTaken is called', (WidgetTester tester) async {
// GIVEN
Uint8List callbackImage;
var expectedImage = base64.decode(
'iVBORw0KGgoAAAANSUh'
'EUgAAAAEAAAABCAYAAAA'
'fFcSJAAAADUlEQVR42mNk+'
'P+/HgAFhAJ/wlseKgAAAA'
'BJRU5ErkJggg==',
);
var randomStringGenerator = () => 'test_simple_photo';
// Join file path
final file = File(join(
directory.path,
'${randomStringGenerator()}.png',
));
// write image to expected path
file.writeAsBytesSync(expectedImage);
var cameraController = MockCameraController();
when(cameraController.initialize()).thenAnswer((_) => Future.value());
when(cameraController.value).thenReturn(
CameraValue(
isInitialized: false,
),
);
var photoPage = SimplePhotoPage(
cameraController: cameraController,
randomStringGenerator: randomStringGenerator,
onPhotoTaken: (image) => callbackImage = image,
);
// WHEN
await tester.pumpWidget(
MaterialApp(
home: photoPage,
),
);
await tester.tap(find.byType(FloatingActionButton));
await tester.pumpAndSettle();
// THEN
expect(callbackImage, expectedImage);
});
});
}
However, this test fails and when debugging the test exits at但是,此测试失败,调试时测试退出
final image = await file.readAsBytes();
without any error or really any sign that anything went wrong.没有任何错误,也没有任何迹象表明出现任何问题。 The interesting thing is when I switch to their sync counterparts ( readAsBytesSync()
, deleteSync()
), the test passes.有趣的是,当我切换到它们的同步对应项( readAsBytesSync()
、 deleteSync()
)时,测试通过了。
From reading the source code for the dart io lib it seems readAsBytes
runs in a separate isolate and it doesn't seem to complete the readAsBytes()
future in the test isolate.从阅读 dart io lib 的源代码readAsBytes
似乎在单独的隔离中运行,并且它似乎没有在测试隔离中完成readAsBytes()
未来。 I would like not to use the sync version of this method.我不想使用此方法的同步版本。 Do you guys know how to accomplish this?大家知道怎么实现吗?
I also faced this issue, and wasn't able to figure out why the file read never executed (or no exceptions were thrown).我也遇到了这个问题,无法弄清楚为什么读取的文件从未执行过(或没有抛出异常)。
I ended up is using file package to replace 'dart:io' to pass in an interface to the widget for accessing the filesystem.我最终使用文件包来替换 'dart:io' 以将接口传递给小部件以访问文件系统。 This creates a constructor as such这将创建一个构造函数
import 'package:file/memory.dart';
import 'package:file/file.dart'
class FSWidget extends StatefulWidget{
FileSystem _fs;
FSWidget({FilesSystem? fileSystem}): _fs = fileSystem?? MemoryFileSystem();
@override
_PostScreenState createState() => _PostScreenState();
}
}
This allows you to use to pass in your own filesystem for testing这允许您使用传入您自己的文件系统进行测试
Your temp file system access code becomes您的临时文件系统访问代码变为
...
final filename = widget.randomStringGenerator?.call() ?? '';
final tempDirectory = await widget._fs.systemTempDirectory.createTemp('tempDir');
final outputFile = tempDirectory.childFile('${filename}.png');
await widget.cameraController?.takePicture(outputFile.path);
widget.onPhotoTaken(outputFile);
await outputFile.delete();
...
You can now pass in a reference to your test filesystem to your widget您现在可以将测试文件系统的引用传递给您的小部件
testWidgets('onPictureTaken is called', (WidgetTester tester) async {
FileSystem testFS = MemoryFileSystem();
// Add stuff to the filesystem
...
await tester.pumpWidget(
MaterialApp(
home: FSWidget(filesystem: testFS),
),
...
// Expect stuff from the filesystem
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.