如何使用 MockBloc 实现 widget 测试?
How to implement widget tests by using MockBloc?
我正在尝试实施小部件测试以测试登录表单。此测试取决于我使用 MockBloc 模拟的集团。但是,它会引发以下错误:
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK╞════════════════════════════════════════════════════
The following StateError was thrown running a test:
Bad state: No method stub was called from within `when()`. Was a real method called, or perhaps an
extension method?
我在下面的 中发现了类似的错误,但我看不出它能如何帮助我解决我的问题。
我也看了下面file on gitlub, which is an example of a widget test by using bloc_test. The link can be found on the official website of the Bloc Library - specifically in Todos App in Flutter using the Bloc library.
但是,该示例使用的是 bloc_test: ^3.0.1
,而我使用的是 bloc_test: ^8.0.0
,可以在 here.
中找到
这是一个最小的例子:
- 登录表单小部件
class LoginForm extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Form(
key: '_loginForm',
child: Column(
children: <Widget>[
...
BlocConsumer<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
...
},
builder: (context, state) {
if (state is AuthenticationInitial) {
...
} else if (state is LoggingIn || state is LoggedIn) {
...
} else if (state is Error) {
return Column(
children: <Widget>[
...
Message(
message: state.message,
messageContainerWidth: 290,
messageContainerHeight: 51,
),
...
],
);
}
}
),
],
),
);
}
}
- 消息小工具
class Message extends StatelessWidget {
final String message;
final double messageContainerWidth;
final double messageContainerHeight;
...
@override
Widget build(BuildContext context) {
return Container(
width: messageContainerWidth,
height: messageContainerHeight,
child: Center(
child: message != ""
? Text(
message,
textAlign: TextAlign.center,
style: TextStyle(
color: Color.fromRGBO(242, 241, 240, 1),
fontSize: 15,
),
)
: child,
),
);
}
}
- 小部件测试(我想测试当身份验证状态为错误时是否显示消息)
...
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
...
// Mocking my LoginUser usecase
class MockLoginUser extends Mock implements LoginUser {}
// Mocking my bloc
class MockAuthenticationBloc
extends MockBloc<AuthenticationEvent, AuthenticationState>
implements AuthenticationBloc {}
class AuthenticationStateFake extends Fake implements AuthenticationState {}
void main() {
MockLoginUser mockLoginUser;
setUpAll(() {
registerFallbackValue<AuthenticationState>(AuthenticationStateFake());
});
setUp(() {
mockLoginUser = MockLoginUser();
authenticationBloc = AuthenticationBloc(loginUser: mockLoginUser);
});
group('Login', () {
testWidgets(
'should show a Message when the Authentication state is Error',
(WidgetTester tester) async {
whenListen(
authenticationBloc,
Stream.fromIterable(
[
LoggingIn(),
Error(
message: 'Some error message',
),
],
),
initialState: AuthenticationInitial(),
);
final widget = LoginForm();
await tester.pumpWidget(
BlocProvider<AuthenticationBloc>(
create: (context) => authenticationBloc,
child: MaterialApp(
title: 'Widget Test',
home: Scaffold(body: widget),
),
),
);
await tester.pumpAndSettle();
final messageWidget = find.byType(Message);
expect(messageWidget, findsOneWidget);
});
});
}
如果有人能帮助我解决错误,或者让我知道实现小部件测试的另一种方法,我将不胜感激。
提前致谢!
我解决了这个问题,我想分享答案,以防有人发现同样的问题。
首先,这个 link 真的很有帮助。
解决方案是按以下方式更改 Widget Test:
...
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
...
class MockAuthenticationBloc
extends MockBloc<AuthenticationEvent, AuthenticationState>
implements AuthenticationBloc {}
class AuthenticationStateFake extends Fake implements AuthenticationState {}
class AuthenticationEventFake extends Fake implements AuthenticationEvent {}
void main() {
group('Login', () {
setUpAll(() {
registerFallbackValue<AuthenticationState>(AuthenticationStateFake());
registerFallbackValue<AuthenticationEvent>(AuthenticationEventFake());
});
testWidgets(
'should show a Message when the Authentication state is Error',
(WidgetTester tester) async {
// arrange
final mockAuthenticationBloc = MockAuthenticationBloc();
when(() => mockAuthenticationBloc.state).thenReturn(
LoggingIn(), // the desired state
);
// find
final widget = LoginForm();
final messageWidget = find.byType(Message);
// test
await tester.pumpWidget(
BlocProvider<AuthenticationBloc>(
create: (context) => mockAuthenticationBloc,
child: MaterialApp(
title: 'Widget Test',
home: Scaffold(body: widget),
),
),
);
await tester.pumpAndSettle();
// expect
expect(messageWidget, findsOneWidget);
});
});
}
我正在尝试实施小部件测试以测试登录表单。此测试取决于我使用 MockBloc 模拟的集团。但是,它会引发以下错误:
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK╞════════════════════════════════════════════════════
The following StateError was thrown running a test:
Bad state: No method stub was called from within `when()`. Was a real method called, or perhaps an
extension method?
我在下面的
我也看了下面file on gitlub, which is an example of a widget test by using bloc_test. The link can be found on the official website of the Bloc Library - specifically in Todos App in Flutter using the Bloc library.
但是,该示例使用的是 bloc_test: ^3.0.1
,而我使用的是 bloc_test: ^8.0.0
,可以在 here.
这是一个最小的例子:
- 登录表单小部件
class LoginForm extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Form(
key: '_loginForm',
child: Column(
children: <Widget>[
...
BlocConsumer<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
...
},
builder: (context, state) {
if (state is AuthenticationInitial) {
...
} else if (state is LoggingIn || state is LoggedIn) {
...
} else if (state is Error) {
return Column(
children: <Widget>[
...
Message(
message: state.message,
messageContainerWidth: 290,
messageContainerHeight: 51,
),
...
],
);
}
}
),
],
),
);
}
}
- 消息小工具
class Message extends StatelessWidget {
final String message;
final double messageContainerWidth;
final double messageContainerHeight;
...
@override
Widget build(BuildContext context) {
return Container(
width: messageContainerWidth,
height: messageContainerHeight,
child: Center(
child: message != ""
? Text(
message,
textAlign: TextAlign.center,
style: TextStyle(
color: Color.fromRGBO(242, 241, 240, 1),
fontSize: 15,
),
)
: child,
),
);
}
}
- 小部件测试(我想测试当身份验证状态为错误时是否显示消息)
...
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
...
// Mocking my LoginUser usecase
class MockLoginUser extends Mock implements LoginUser {}
// Mocking my bloc
class MockAuthenticationBloc
extends MockBloc<AuthenticationEvent, AuthenticationState>
implements AuthenticationBloc {}
class AuthenticationStateFake extends Fake implements AuthenticationState {}
void main() {
MockLoginUser mockLoginUser;
setUpAll(() {
registerFallbackValue<AuthenticationState>(AuthenticationStateFake());
});
setUp(() {
mockLoginUser = MockLoginUser();
authenticationBloc = AuthenticationBloc(loginUser: mockLoginUser);
});
group('Login', () {
testWidgets(
'should show a Message when the Authentication state is Error',
(WidgetTester tester) async {
whenListen(
authenticationBloc,
Stream.fromIterable(
[
LoggingIn(),
Error(
message: 'Some error message',
),
],
),
initialState: AuthenticationInitial(),
);
final widget = LoginForm();
await tester.pumpWidget(
BlocProvider<AuthenticationBloc>(
create: (context) => authenticationBloc,
child: MaterialApp(
title: 'Widget Test',
home: Scaffold(body: widget),
),
),
);
await tester.pumpAndSettle();
final messageWidget = find.byType(Message);
expect(messageWidget, findsOneWidget);
});
});
}
如果有人能帮助我解决错误,或者让我知道实现小部件测试的另一种方法,我将不胜感激。
提前致谢!
我解决了这个问题,我想分享答案,以防有人发现同样的问题。
首先,这个 link 真的很有帮助。
解决方案是按以下方式更改 Widget Test:
...
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
...
class MockAuthenticationBloc
extends MockBloc<AuthenticationEvent, AuthenticationState>
implements AuthenticationBloc {}
class AuthenticationStateFake extends Fake implements AuthenticationState {}
class AuthenticationEventFake extends Fake implements AuthenticationEvent {}
void main() {
group('Login', () {
setUpAll(() {
registerFallbackValue<AuthenticationState>(AuthenticationStateFake());
registerFallbackValue<AuthenticationEvent>(AuthenticationEventFake());
});
testWidgets(
'should show a Message when the Authentication state is Error',
(WidgetTester tester) async {
// arrange
final mockAuthenticationBloc = MockAuthenticationBloc();
when(() => mockAuthenticationBloc.state).thenReturn(
LoggingIn(), // the desired state
);
// find
final widget = LoginForm();
final messageWidget = find.byType(Message);
// test
await tester.pumpWidget(
BlocProvider<AuthenticationBloc>(
create: (context) => mockAuthenticationBloc,
child: MaterialApp(
title: 'Widget Test',
home: Scaffold(body: widget),
),
),
);
await tester.pumpAndSettle();
// expect
expect(messageWidget, findsOneWidget);
});
});
}