测试小部件时,在 BlocListener 上测试失败
Test failing on BlocListener in flutter when testing widget
我有两个测试,检查在使用 BlocListener 流式传输和处理登录状态时是否显示小吃店。
void main() async {
AuthenticationRepositoryMock _authenticationRepositoryMock;
LoginBlocMock _loginBloc;
final fireBaseUserMock = FirebaseUserMock();
final randomValidPassword = "password";
final buttonFinder = find.byKey(Key('credentials_button'));
final snackBarFailureFinder = find.byKey(Key("snack_bar_failure"));
final snackBarLoadingFinder = find.byKey(Key("snack_bar_loading"));
final emailFieldFinder = find.byKey(Key('email_field'));
final passwordFieldFinder = find.byKey(Key('password_field'));
Widget makeTestableWidget() {
return BlocProvider<LoginBloc>(
builder: (context) => _loginBloc,
child: MaterialApp(
home: Scaffold(
body: LoginPage(),
)
),
);
}
setUp((){
_authenticationRepositoryMock = AuthenticationRepositoryMock();
_loginBloc = LoginBlocMock(authenticationRepository: _authenticationRepositoryMock);
});
testWidgets('Show snack bar when state is LoginFailure', (WidgetTester tester) async {
//Arrange
var expectedStates = [
LoginInitial(),
LoginFailure(error: "Could not find user. Please try different credentials")
];
whenListen(_loginBloc, Stream.fromIterable(expectedStates));
//Act
await tester.pumpWidget(makeTestableWidget());
expect(snackBarFailureFinder, findsNothing);
await tester.enterText(emailFieldFinder, fireBaseUserMock.email);
await tester.pumpAndSettle();
await tester.enterText(passwordFieldFinder, randomValidPassword);
await tester.pumpAndSettle();
await tester.tap(buttonFinder);
await tester.pumpAndSettle();
//Assert
expect(snackBarFailureFinder, findsOneWidget);
});
//FAILING FOR NO REASON!
testWidgets('Show snack bar when state is LoginLoading', (WidgetTester tester) async {
//Arrange
var expectedStates = [
LoginInitial(),
LoginLoading()
];
whenListen(_loginBloc, Stream.fromIterable(expectedStates));
//Act
await tester.pumpWidget(makeTestableWidget());
expect(snackBarLoadingFinder, findsNothing);
await tester.enterText(emailFieldFinder, fireBaseUserMock.email);
await tester.pumpAndSettle();
await tester.enterText(passwordFieldFinder, randomValidPassword);
await tester.pumpAndSettle();
await tester.tap(buttonFinder);
await tester.pumpAndSettle();
//Assert
expect(snackBarLoadingFinder, findsOneWidget);
});
}
这两个测试正在测试页面上的以下小部件:
BlocListener<LoginBloc, LoginState>(
listener: (context, state){
if(state is LoginFailure){
Scaffold.of(context)
.showSnackBar(SnackBar(
key: Key("snack_bar_failure"),
content: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [Text('Login Failure'), Icon(Icons.error)],
),
backgroundColor: Colors.redAccent
));
}
if (state is LoginLoading) {
Scaffold.of(context)
.showSnackBar(SnackBar(
key: Key("snack_bar_loading"),
content: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [Text('Logging in...'), Spinner()],
),
backgroundColor: Colors.blueAccent
));
}
}
第一个用键 'snack_bar_failure' 查找小吃店的测试通过了,但第二个测试没有通过。简直是一样的测试,一样的设置,只是预期的状态不同,小吃店的钥匙不一样snack_bar_loading
.
第二次测试失败并显示以下错误消息:
The following TestFailure object was thrown running a test:
Expected: exactly one matching node in the widget tree
Actual: ?:<zero widgets with key [<'snack_bar_loading'>] (ignoring offstage widgets)>
Which: means none were found but one was expected
我错过了什么吗?
问题已在问题(https://github.com/felangel/bloc/issues/655)中得到解答。希望对您有所帮助!
我有两个测试,检查在使用 BlocListener 流式传输和处理登录状态时是否显示小吃店。
void main() async {
AuthenticationRepositoryMock _authenticationRepositoryMock;
LoginBlocMock _loginBloc;
final fireBaseUserMock = FirebaseUserMock();
final randomValidPassword = "password";
final buttonFinder = find.byKey(Key('credentials_button'));
final snackBarFailureFinder = find.byKey(Key("snack_bar_failure"));
final snackBarLoadingFinder = find.byKey(Key("snack_bar_loading"));
final emailFieldFinder = find.byKey(Key('email_field'));
final passwordFieldFinder = find.byKey(Key('password_field'));
Widget makeTestableWidget() {
return BlocProvider<LoginBloc>(
builder: (context) => _loginBloc,
child: MaterialApp(
home: Scaffold(
body: LoginPage(),
)
),
);
}
setUp((){
_authenticationRepositoryMock = AuthenticationRepositoryMock();
_loginBloc = LoginBlocMock(authenticationRepository: _authenticationRepositoryMock);
});
testWidgets('Show snack bar when state is LoginFailure', (WidgetTester tester) async {
//Arrange
var expectedStates = [
LoginInitial(),
LoginFailure(error: "Could not find user. Please try different credentials")
];
whenListen(_loginBloc, Stream.fromIterable(expectedStates));
//Act
await tester.pumpWidget(makeTestableWidget());
expect(snackBarFailureFinder, findsNothing);
await tester.enterText(emailFieldFinder, fireBaseUserMock.email);
await tester.pumpAndSettle();
await tester.enterText(passwordFieldFinder, randomValidPassword);
await tester.pumpAndSettle();
await tester.tap(buttonFinder);
await tester.pumpAndSettle();
//Assert
expect(snackBarFailureFinder, findsOneWidget);
});
//FAILING FOR NO REASON!
testWidgets('Show snack bar when state is LoginLoading', (WidgetTester tester) async {
//Arrange
var expectedStates = [
LoginInitial(),
LoginLoading()
];
whenListen(_loginBloc, Stream.fromIterable(expectedStates));
//Act
await tester.pumpWidget(makeTestableWidget());
expect(snackBarLoadingFinder, findsNothing);
await tester.enterText(emailFieldFinder, fireBaseUserMock.email);
await tester.pumpAndSettle();
await tester.enterText(passwordFieldFinder, randomValidPassword);
await tester.pumpAndSettle();
await tester.tap(buttonFinder);
await tester.pumpAndSettle();
//Assert
expect(snackBarLoadingFinder, findsOneWidget);
});
}
这两个测试正在测试页面上的以下小部件:
BlocListener<LoginBloc, LoginState>(
listener: (context, state){
if(state is LoginFailure){
Scaffold.of(context)
.showSnackBar(SnackBar(
key: Key("snack_bar_failure"),
content: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [Text('Login Failure'), Icon(Icons.error)],
),
backgroundColor: Colors.redAccent
));
}
if (state is LoginLoading) {
Scaffold.of(context)
.showSnackBar(SnackBar(
key: Key("snack_bar_loading"),
content: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [Text('Logging in...'), Spinner()],
),
backgroundColor: Colors.blueAccent
));
}
}
第一个用键 'snack_bar_failure' 查找小吃店的测试通过了,但第二个测试没有通过。简直是一样的测试,一样的设置,只是预期的状态不同,小吃店的钥匙不一样snack_bar_loading
.
第二次测试失败并显示以下错误消息:
The following TestFailure object was thrown running a test:
Expected: exactly one matching node in the widget tree
Actual: ?:<zero widgets with key [<'snack_bar_loading'>] (ignoring offstage widgets)>
Which: means none were found but one was expected
我错过了什么吗?
问题已在问题(https://github.com/felangel/bloc/issues/655)中得到解答。希望对您有所帮助!