Flutter: readAsBytes/readAsString в тестах виджетов
Я пытаюсь проверить
StatefulWidget
со следующими
onPressed
функция.
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);
}
},
),
и следующий тест виджета:
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);
});
});
}
Однако этот тест не проходит, и при отладке тест завершается на
final image = await file.readAsBytes();
без каких-либо ошибок или признаков того, что что-то пошло не так. Интересно, когда я переключаюсь на их аналоги для синхронизации (readAsBytesSync()
,
deleteSync()
), тест пройден.
При чтении исходного кода библиотеки dart io кажется
readAsBytes
работает в отдельном изоляторе и, похоже, не завершает
readAsBytes()
будущее в тестовом изоляте. Я бы не хотел использовать синхронизирующую версию этого метода. Вы знаете, как этого добиться?
1 ответ
Я также столкнулся с этой проблемой и не смог понять, почему чтение файла никогда не выполнялось (или не возникало никаких исключений).
В итоге я использовал пакет файлов, чтобы заменить dart: io, чтобы передать интерфейс виджету для доступа к файловой системе. Это создает конструктор как таковой
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();
}
}
Это позволяет вам использовать для передачи вашей собственной файловой системы для тестирования
Ваш код доступа к временной файловой системе станет
...
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();
...
Теперь вы можете передать ссылку на вашу тестовую файловую систему своему виджету.
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