如何使用MockBloc实现widget测试?

2023-12-22

我正在尝试实现小部件测试以测试登录表单。该测试取决于我使用 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?

我在下面发现了类似的错误link https://stackoverflow.com/questions/55424575/bad-state-mock-method-was-not-called-within-when-was-a-real-method-called,但我不知道这如何能帮助我解决我的问题。

我还查看了以下内容github上的文件 https://github.com/brianegan/flutter_architecture_samples/blob/master/bloc_library/test/widgets/stats_tab_test.dart,这是使用 bloc_test 进行小部件测试的示例。该链接可以在 Bloc 图书馆的官方网站上找到 - 特别是在Flutter 中使用 Bloc 库的 Todos 应用 https://bloclibrary.dev/#/fluttertodostutorial.

但是,该示例正在使用bloc_test: ^3.0.1当我使用时bloc_test: ^8.0.0,可以找到here https://pub.dev/packages/bloc_test.

这是一个最小的例子:

  • 登录表单小部件
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 https://gist.github.com/reinaldomoreira/98e6d8ce1c296defe66fb064bbc2733b真的很有帮助。

解决方案是改变小部件测试通过以下方式:

...
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);
    });
  });
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用MockBloc实现widget测试? 的相关文章

随机推荐

  • 如何判断 Rails 代码是通过 rake 还是 script/generate 运行?

    我有一个有点重的插件 项目符号 配置有 Growl 通知 如果我只是运行 rake 任务或生成器 我不想启用它 因为它在这些情况下没有用 有什么方法可以判断是否是这种情况吗 就这么简单 if rails rake task puts Gue
  • 什么类型的序列化在幕后使用 Wcf?

    我知道 net 中有 3 种类型的序列化 Soap Xml Binary Wcf 指示 DataContract 属性也序列化 但是通过what 二进制不是 我知道 那么通过什么机制 它是为给定端点定义的绑定 它指定了序列化机制 例如 ba
  • python seed() 不保持相同的序列

    我正在使用 random seed 来尝试保持 random sample 与我从列表中采样更多值相同 并且在某些时候数字会发生变化 我认为的一个目的Seed 函数的作用是保持数字相同 这是我做的一个测试 以证明它不会保留相同的数字 imp
  • 编译器在转换整型常量时做什么?

    使用以下宏 define MIN SWORD signed int 0x8000 例如以下表达式 signed long s32 if s32 lt signed long MIN SWORD 预计要做以下检查 if s32 lt 3276
  • 数据表中的字典

    说我有3个Dictionary
  • 应用程序缓存清单+本地存储大小限制

    我正在构建一个可能有大量离线存储需求的应用程序 我想知道是否可以同时使用离线缓存清单 5MB 和本地存储 5MB 来使用 10MB 存储 请注意 这是一个 Intranet 应用程序 因此我们可以控制设备 我已经在 Chrome Firef
  • 没有模糊视图效果的 UIAlertController 操作表

    我在用着UIAlertController对于一些行动 但我不太喜欢模糊视图效果在操作组视图中 参见下面的屏幕截图 我正在尝试消除这种模糊效果 我在网上查了一下 没有找到任何APIUIAlertController这样就可以消除这种模糊效果
  • php + mysql,按名称排序+从特定id开始

    MySQL id name 1 Joe 2 Craig 3 Shawn 4 Ryan 5 Seth PHP a mysql query SELECT FROM table name ORDER BY name DESC 但我想做的是 我想从
  • Firebird 交易计数超出

    我们有一个运行 Firebird 数据库的实现 但出现以下错误 超出实施限制 超出交易计数 执行备份和恢复以使数据库再次可操作 我们知道如何通过使数据库只读 执行备份和恢复以及再次读写来解决此问题 但是我们不太确定导致此问题的原因 我感觉交
  • > 和线程' aria-label='Rust 生命周期与 mpsc::Sender> 和线程'> Rust 生命周期与 mpsc::Sender> 和线程

    我正在创建一个多线程应用程序 在其中创建一个接收通道和一个用于保存发送通道的结构 稍后由实现使用 但是 我通过通道发送的类型具有生命周期规范 这种类型是websocket message Message来自 rust websocket 库
  • 如何在 zenframework 2 上配置学说命令行工具

    我在 zendframework 2 上使用原则 2 我已经正确配置了两者 并且它们都正常工作 不过我想用学说的命令行工具生成实体等 我遵循了学说的说明 并在应用程序的根目录中创建了一个 cli config php 页面 http doc
  • 如何防止 DIV 扩展并占据所有可用宽度?

    在下面的 HTML 中 我希望图像周围的框架能够紧贴 不要拉伸并占据父容器中的所有可用宽度 我知道有几种方法可以做到这一点 包括可怕的事情 例如手动将其宽度设置为特定数量的像素 但是什么是right way Edit 一个答案建议我关闭 d
  • ARRAY_CONTAINS hive 中的多个值

    有没有一种方便的方法来使用 hive 中的 ARRAY CONTAINS 函数来搜索数组列中的多个条目 而不仅仅是一个 所以而不是 WHERE ARRAY CONTAINS array val1 OR ARRAY CONTAINS arra
  • 如何在ios中调整uilabel的角度[重复]

    这个问题在这里已经有答案了 i m creating an iphone app in that application i want to angle the label according to the attached screen
  • iOS 8 CoreData 问题:recordChangeSnapshot:forObjectID:: 录制时全局 ID 可能不是临时的

    我正在将我的应用程序从 iOS 7 迁移到 iOS 8 当我尝试保存核心数据上下文时 我在 Xcode 中收到以下错误 iOS 7 和 Xcode 5 中不存在此错误 它会在下面的行中抛出异常 NSError saveError nil i
  • Django:“sys.path”应该是什么?

    开发 Django 应用程序时 什么是sys path应该包含 包含项目的目录 或项目的目录 或两者 sys path应该并且将会有项目的目录 根据您的设置 它还可能包含包含项目的目录 但是 如果这个问题背后的动机是确保可以找到某些文件 那
  • 如何在Windows批处理文件中循环连接字符串?

    我熟悉 Unix shell 脚本编写 但对 Windows 脚本编写不熟悉 我有一个包含 str1 str2 str3 str10 的字符串列表 我想这样做 for string in string list do var string
  • 调用未定义的方法 Maatwebsite\Excel\Excel::load()

    我正在尝试使用 maatwebsite 3 0 导入 Excel 文件 xlsx 如何修复此错误 调用未定义的方法 Maatwebsite Excel Excel load 我的控制器 public function importsave
  • CGMutablePathRef 的自动释放?

    我正在为 iPhone 开发 我想通过 CGPathCreateMutable 创建一个可变路径 并且我想从创建它的函数中返回它 我应该在完成后调用 CGPathRelease 但既然我要归还它 我希望自动释放它 由于 Quartz 路径是
  • 如何使用MockBloc实现widget测试?

    我正在尝试实现小部件测试以测试登录表单 该测试取决于我使用 MockBloc 嘲笑的块 但是 它会引发以下错误 EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK The following StateEr