ウィジェットテスト、特にナビゲーションテストを実行しようとしています。ブロックアーキテクチャを使用しています。ブロックにストリームを設定すると、ブロック内の一連のイベントがトリガーされ、サーバーコールからセッション情報が取得されます(これにより、セッション情報オブジェクトのフューチャーが返されます)。サーバーコールが成功すると、ログインストリームが設定され、ウィジェットには、このストリームへのストリームサブスクリプションがあり、次の画面に移動します。
私はmockitoを使用してサーバー呼び出しをモックし、サーバー呼び出しをスタブして将来の成功応答を返しています。問題は、私がpumpAndSettle()
を呼び出しているときに、未来が完了して成功の応答を返すのを待っていないため、タイムアウトになることです。
明確に説明していない場合はお詫びしますが、サンプルコードを次に示します。
login_bloc.Dart
_class LoginBloc {
LoginRepository _loginRepository;
final String searchKeyword = "special-keyword";
final _urlString = PublishSubject<String>();
final _isLoggedIn = BehaviorSubject<bool>(seedValue: false);
final _errorMessage = PublishSubject<String>();
Observable<bool> get isLoggedIn => _isLoggedIn.stream;
Observable<String> get isErrorState => _errorMessage.stream;
LoginBloc({LoginRepository loginRepository})
: _loginRepository = loginRepository ?? LoginRepository() {
// Listen on the _urlString stream to call the function which checks for the special keyword and if a match is found make a server call
_urlString.stream.listen((String url) {
_authorizationFullService(url);
});
}
// Search for special keyword and if a match is found call the server call function
void _authorizationFullService(String url) {
if (url.contains(searchKeyword)) {
int index = url.indexOf(searchKeyword);
String result = url.substring(index + searchKeyword.length);
result = result.trim();
String decodedUrl = Uri.decodeFull(result);
if (decodedUrl != null && decodedUrl.length > 0) {
_fullServiceServerCall(decodedUrl);
} else {
_isLoggedIn.sink.add(false);
}
}
}
// Call server call function from repository which returns a future of the Authorization object
void _fullServiceServerCall(String decodedUrl) {
_loginRepository
.getSession(decodedUrl)
.then(_handleSuccessAuthorization)
.catchError(_handleErrorState);
}
// Handle success response and set the login stream
void _handleSuccessAuthorization(Authorization authorization) {
if (authorization != null && authorization.idnumber != 0) {
_isLoggedIn.sink.add(true);
} else {
_isLoggedIn.sink.add(false);
}
}
// Handle error response and set the error stream
void _handleErrorState(dynamic error) {
_isLoggedIn.sink.add(false);
_errorMessage.sink.add(error.toString());
}
void dispose() {
_urlString.close();
_isLoggedIn.close();
_errorMessage.close();
}
}
_
widget_test.Dart
_group('Full Login Navigation test', () {
LoginRepository mockLoginRepository;
LoginBloc loginBloc;
NotificationBloc notificationBloc;
NavigatorObserver mockNavigatorObserver;
Authorization _auth;
String testUrl;
setUp(() {
mockLoginRepository = MockLoginRepository();
_auth = Authorization((auth) => auth
..param1 = "foo"
..param2 = "bar"
..param3 = "foobar"
..param4 = "barfoo");
loginBloc = LoginBloc(loginRepository: mockLoginRepository);
mockNavigatorObserver = MockNavigatorObserver();
testUrl = "http://test.test.com";
});
Future<Null> _buildFullLoginPage(LoginBloc loginBloc,
NotificationBloc notificationBloc, WidgetTester tester) async {
when(mockLoginRepository.getSession(testUrl))
.thenAnswer((_) => Future.value(_auth));
await tester.pumpWidget(LoginBlocProvider(
child: NotificationBlocProvider(
child: MaterialApp(
home: LoginFullService(),
onGenerateRoute: NavigationRoutes.routes,
navigatorObservers: [mockNavigatorObserver],
),
notificationBloc: notificationBloc,
),
loginBloc: loginBloc,
));
//TODO: Remove casting to dynamic after Dart sdk bug fix: https://github.com/Dart-lang/mockito/issues/163
verify(mockNavigatorObserver.didPush(any, any) as dynamic);
loginBloc.getAuthorization(
"http://testing.testing.com?search-keyword=http%3A%2F%2Ftest.test.com");
}
testWidgets('Navigate to landing page on correct login url',
(WidgetTester tester) async {
await _buildFullLoginPage(loginBloc, notificationBloc, tester);
await tester.pumpAndSettle();
expect(find.byKey(Key('webview_scaffold')), findsNothing);
//TODO: Remove casting to dynamic after Dart sdk bug fix: https://github.com/Dart-lang/mockito/issues/163
verify(mockNavigatorObserver.didPush(any, any) as dynamic);
});
});
_
ウィジェットを実行すると、testWidgets
内のtester.pumpAndSettle()
が将来が完了する前にタイムアウトします。これはエラーログです:
_══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following assertion was thrown running a test:
pumpAndSettle timed out
When the exception was thrown, this was the stack:
#0 WidgetTester.pumpAndSettle.<anonymous closure> (package:flutter_test/src/widget_tester.Dart:299:11)
<asynchronous suspension>
#3 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.Dart:69:41)
#4 WidgetTester.pumpAndSettle (package:flutter_test/src/widget_tester.Dart:295:27)
#5 main.<anonymous closure>.<anonymous closure> (file:///Users/ssiddh/Documents/projects/mobile-flutter/test/ui/pages/login/login_full_test.Dart:114:20)
<asynchronous suspension>
#6 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.Dart:72:23)
#7 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.Dart:555:19)
<asynchronous suspension>
#10 TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.Dart:539:14)
#11 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.Dart:883:24)
#17 AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.Dart:880:15)
#18 testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.Dart:71:22)
#19 Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test/src/backend/declarer.Dart:168:27)
<asynchronous suspension>
#20 Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test/src/backend/invoker.Dart:249:15)
<asynchronous suspension>
#25 Invoker.waitForOutstandingCallbacks (package:test/src/backend/invoker.Dart:246:5)
#26 Declarer.test.<anonymous closure>.<anonymous closure> (package:test/src/backend/declarer.Dart:166:33)
#31 Declarer.test.<anonymous closure> (package:test/src/backend/declarer.Dart:165:13)
<asynchronous suspension>
#32 Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test/src/backend/invoker.Dart:403:25)
<asynchronous suspension>
#46 _Timer._runTimers (Dart:isolate/runtime/libtimer_impl.Dart:382:19)
#47 _Timer._handleMessage (Dart:isolate/runtime/libtimer_impl.Dart:416:5)
#48 _RawReceivePortImpl._handleMessage (Dart:isolate/runtime/libisolate_patch.Dart:169:12)
(elided 30 frames from class _FakeAsync, package Dart:async, and package stack_trace)
_
どんな助けやフィードバックにも本当に感謝します。
テストをラップしてみてください
testWidgets('Navigate to landing page on correct login url',
(WidgetTester tester) async {
await tester.runAsync(() async {
// test code here
});
});