简体   繁体   English

如何使用 MockBloc 实现小部件测试?

[英]How to implement widget tests by using MockBloc?

I'm trying to implement a Widget Test in order to test a login form.我正在尝试实现小部件测试以测试登录表单。 This test depends on a bloc which I'm mocking by using MockBloc.这个测试依赖于一个使用 MockBloc 的块,我是 mocking。 However, it throws the following error:但是,它会引发以下错误:

══╡ 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?

I found a similar error in the following link , but I do not see how that can help me to solve my problem.我在以下链接中发现了一个类似的错误,但我看不出它如何帮助我解决我的问题。

I also looked at the following file on gitlub , which is an example of a widget test by using bloc_test.我还在gitlub 上查看了以下文件,这是使用 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 库的官方网站上找到——具体是在使用 Bloc 库的 Flutter 中的 Todos App 中

However, that example is using bloc_test: ^3.0.1 while I'm using bloc_test: ^8.0.0 , which can be found here .但是,该示例使用bloc_test: ^3.0.1而我使用bloc_test: ^8.0.0 ,可以在此处找到。

Here is a minimal example:这是一个最小的例子:

  • LoginForm Widget登录表单小部件
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,
                    ),
                    ...
                  ],
                );
               }
             }
           ),
        ],
      ),
    );
  }
}
  • Message Widget消息小部件
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,
      ),
    );
  }
}
  • Widget Test (I want to test that a Message is shown when the Authentication state is Error)小部件测试(我想测试验证 state 为错误时是否显示消息)
...
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);
    });
  });
}

I will really appreciate it if someone can help me to solve the error, or can let me know another way to implement the widget tests.如果有人可以帮助我解决错误,或者可以让我知道实现小部件测试的另一种方法,我将不胜感激。

Thanks in advance!提前致谢!

I solved the problem, I would like to share the answer, in case someone finds out the same problem.我解决了这个问题,我想分享答案,以防有人发现同样的问题。

First of all, this link was really helpful.首先,这个链接真的很有帮助。

The solution was to change the Widget Test in the following way:解决方案是通过以下方式更改小部件测试

...
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);
    });
  });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM