我有 Widget 与 NetworkImage (到目前为止,硬编码的网址) .我想对这个Widget进行小部件测试,但是当我运行小部件测试时,我得到了404(url是100%有效) .如何使 NetworkImages 自己加载或(这会更好) ignore them 以便我的测试不会因404而失败?
Widget
NetworkImage
NetworkImages
我用
import 'package:flutter/services.dart' show createHttpClient; final imageUri = Uri.parse('http://example.com$dummyImagePath'); testWidgets( ...) { createHttpClient = createMockImageHttpClient; await tester.pumpWidget(new TestWrapperWidget( child: (_) => new ImageWidget(name: text, url: imageUri))); }
import 'dart:async' show Future; import 'package:http/http.dart' show Client, Response; import 'package:http/testing.dart' show MockClient; import 'dummy_image_data.dart' show dummyImageData; const String dummyImagePath = '/image.jpg'; Client createMockImageHttpClient() => new MockClient((request) { switch (request.url.path) { case dummyImagePath: return new Future<Response>.value(new Response.bytes( dummyImageData, 200, request: request, headers: {'Content-type': 'image/jpg'})); default: return new Future<Response>.value(new Response('', 404)); } });
Uint8List get dummyImageData => BASE64.decode(dummyJpgImageBase64);
(我使用http://base64.wutils.com/encoding-online/创建了图像数据Base64)
const String dummyAvatarJpgImageBase64 = '/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIi' ... 'itf93F+MLRdehP4ZutvWj8m+rjzpz//Z';
这样,当我使用 flutter run -t test/image_test.dart 启动时,测试也可以工作,但图像数据也可以从图像文件中提供,以进行正常的测试运行 .
flutter run -t test/image_test.dart
Using the mockito package
image_mock_http_client.dart
import 'dart:async' show Future, Stream; import 'dart:io' show HttpClient, HttpClientRequest, HttpClientResponse, HttpHeaders, HttpOverrides, HttpStatus, SecurityContext; import '.dummy_image_data.dart'; import 'package:mockito/mockito.dart' show Mock, any, anyNamed, captureAny, throwOnMissingStub, when; const String dummyAvatarImagePath = '/avatar.jpg'; class TestHttpOverrides extends HttpOverrides { TestHttpOverrides(this.data); final Map<Uri, List<int>> data; @override HttpClient createHttpClient(SecurityContext context) => createMockImageHttpClient(context, data); } // Returns a mock HTTP client that responds with an image to all requests. MockHttpClient createMockImageHttpClient( SecurityContext _, Map<Uri, List<int>> data) { final client = new MockHttpClient(); final request = new MockHttpClientRequest(); final response = new MockHttpClientResponse(data); final headers = new MockHttpHeaders(); throwOnMissingStub(client); throwOnMissingStub(request); throwOnMissingStub(response); throwOnMissingStub(headers); when<dynamic>(client.getUrl(captureAny)).thenAnswer((invocation) { response.requestedUrl = invocation.positionalArguments[0] as Uri; return new Future<HttpClientRequest>.value(request); }); when(request.headers).thenAnswer((_) => headers); when(request.close()) .thenAnswer((_) => new Future<HttpClientResponse>.value(response)); when(response.contentLength) .thenAnswer((_) => data[response.requestedUrl].length); when(response.statusCode).thenReturn(HttpStatus.ok); when( response.listen( any, cancelOnError: anyNamed('cancelOnError'), onDone: anyNamed('onDone'), onError: anyNamed('onError'), ), ).thenAnswer((invocation) { final onData = invocation.positionalArguments[0] as void Function(List<int>); final onDone = invocation.namedArguments[#onDone] as void Function(); final onError = invocation.namedArguments[#onError] as void Function(Object, [StackTrace]); final cancelOnError = invocation.namedArguments[#cancelOnError] as bool; return new Stream<List<int>>.fromIterable([data[response.requestedUrl]]) .listen(onData, onDone: onDone, onError: onError, cancelOnError: cancelOnError); }); return client; } class MockHttpClient extends Mock implements HttpClient {} class MockHttpClientRequest extends Mock implements HttpClientRequest {} class MockHttpClientResponse extends Mock implements HttpClientResponse { MockHttpClientResponse(this.data); final Map<Uri, List<int>> data; Uri requestedUrl; @override Future<S> fold<S>(S initialValue, S combine(S previous, List<int> element)) => new Stream.fromIterable([data[requestedUrl]]).fold(initialValue, combine); } class MockHttpHeaders extends Mock implements HttpHeaders {}
my_test.dart
import 'image_mock_http_client.dart' show TestHttpOverrides; ... setUp(() async { HttpOverrides.global = new TestHttpOverrides({ 'http://example.com/my_image.png': dummyAvatarImageData, 'http://example.com/other_image.png: dummyPngImageData, }); });
dummyAvatarImageData 和 dummyPngImageData 是 list<int> 并包含图像数据 .
dummyAvatarImageData
dummyPngImageData
list<int>
在窗口小部件测试中,默认HTTP客户端has been replaced,其中一个始终返回400 . 有关如何在flutter_markdown repo以及其他几个地方执行此操作的示例 . 我曾经把它复制并粘贴到每个项目中,但是我做了足够多的时间让它变得很无聊 .
现在有一个库(由我),名为"image_test_utils" . 您可以使用 provideMockedNetworkImages 方法包装窗口小部件测试,该方法将模拟的HTTP客户端替换为始终返回透明图像的HTTP客户端 . 这反过来使你的测试通过 .
provideMockedNetworkImages
pubspec.yaml:
dev_dependencies: image_test_utils: ^1.0.0
my_image_test.dart:
import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:image_test_utils/image_test_utils.dart'; void main() { testWidgets('my image test', (WidgetTester tester) async { provideMockedNetworkImages(() async { /// Now we can pump NetworkImages without crashing our tests. Yay! await tester.pumpWidget( MaterialApp( home: Image.network('https://example.com/image.png'), ), ); /// No crashes. }); }); }
2 回答
我用
(我使用http://base64.wutils.com/encoding-online/创建了图像数据Base64)
这样,当我使用
flutter run -t test/image_test.dart
启动时,测试也可以工作,但图像数据也可以从图像文件中提供,以进行正常的测试运行 .Using the mockito package
image_mock_http_client.dart
my_test.dart
dummyAvatarImageData
和dummyPngImageData
是list<int>
并包含图像数据 .在窗口小部件测试中,默认HTTP客户端has been replaced,其中一个始终返回400 . 有关如何在flutter_markdown repo以及其他几个地方执行此操作的示例 . 我曾经把它复制并粘贴到每个项目中,但是我做了足够多的时间让它变得很无聊 .
现在有一个库(由我),名为"image_test_utils" . 您可以使用
provideMockedNetworkImages
方法包装窗口小部件测试,该方法将模拟的HTTP客户端替换为始终返回透明图像的HTTP客户端 . 这反过来使你的测试通过 .pubspec.yaml:
my_image_test.dart: