【问题标题】:Flutter Bloc Test颤振块测试
【发布时间】:2022-01-11 19:26:34
【问题描述】:

我在一个团队中工作,我们正在使用 Flutter bloc 进行状态管理,但是我们的一个测试用例根本没有任何意义。集团本身运作良好,但测试没有任何意义。

下面是集团本身。

import 'package:vaccify/features/logout/logout.dart';
import 'package:vaccify/features/side_navigation_bar/domain/get_user_name.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:vaccify/features/side_navigation_bar/domain/get_user_profile_pic_url.dart';

part 'auth_event.dart';
part 'auth_state.dart';

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  GetUserName getUserName;
  GetUserProfilePic getUserProfilePic;
  Logout logout;

  AuthBloc(
      {required this.getUserName,
      required this.logout,
      required this.getUserProfilePic})
      : super(NotLoggedIn()) {
    on<AuthLogIn>(_onLogIn);
    on<AuthLogOut>(_onLogOut);
  }

  void _onLogIn(
    AuthLogIn event,
    Emitter<AuthState> emit,
  ) async {
    final name = await getUserName();
    final profilePic = await getUserProfilePic();
    emit(LoggedIn(name, profilePic));
  }

  void _onLogOut(
    AuthLogOut event,
    Emitter<AuthState> emit,
  ) {
    logout();
    emit(NotLoggedIn());
  }
}

现在开始测试

import 'package:bloc_test/bloc_test.dart';
import 'package:vaccify/core/bloc/authentication/auth_bloc.dart';
import 'package:vaccify/features/logout/logout.dart';
import 'package:vaccify/features/side_navigation_bar/domain/get_user_name.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:vaccify/features/side_navigation_bar/domain/get_user_profile_pic_url.dart';

class MockGetUserName extends Mock implements GetUserName {}
class MockGetProfilePicUrl extends Mock implements GetUserProfilePic {}
class MockLogout extends Mock implements Logout {}

void main() {
  late AuthBloc authBloc;
  late MockGetUserName mockGetUserName;
  late MockLogout mockLogout;
  late MockGetProfilePicUrl mockGetProfilePicUrl;

  setUp(() {
    mockGetUserName = MockGetUserName();
    mockLogout = MockLogout();
    mockGetProfilePicUrl = MockGetProfilePicUrl();

    authBloc = AuthBloc(
        getUserName: mockGetUserName,
        logout: mockLogout,
        getUserProfilePic: mockGetProfilePicUrl);
  });

  /// Contains bloc tests for the [AuthBloc] class
  group(
    'AuthBloc',
    () {
      /// Tests that a [LoggedIn] state occurs when the [AuthLogIn] is called.
      blocTest(
        'login',
        build: () {
          when(() => mockGetUserName()).thenAnswer((_) async => "Hello");
          when(() => mockGetProfilePicUrl()).thenAnswer((_) async => "");
          return authBloc;
        },
        act: (AuthBloc bloc) {
          bloc.add(AuthLogIn());
        },
        expect: () => [isA<LoggedIn>()],
      );

      /// Tests that a [NotLoggedIn] state occurs when the [AuthLogOut] is called.
      blocTest(
        'logout',
        build: () {
          when(() => mockGetUserName()).thenAnswer((_) async => "John Smith");
          when(() => mockGetProfilePicUrl()).thenAnswer((_) async => "");
          when(() => mockLogout()).thenAnswer((_) async {});
          return authBloc;
        },
        act: (AuthBloc bloc) {
          bloc.add(AuthLogIn());
          bloc.add(AuthLogOut());
        },

        expect: () => [
          isA<LoggedIn>(),
          isA<NotLoggedIn>(),
        ],
      );
    },
  );
}

第一个测试“登录”工作正常并通过,因为我们添加了一个事件 "AuthLogin()",然后我们期望 LoggedIn 状态

第二个测试“注销”是问题所在,因为我们要添加两个事件 AuthLogin() 和 AuthLogOut(),因为您必须先登录才能注销。 然后我们分别期望 LoggedIn 和 NotLoggedIn 状态。

测试失败并显示以下消息

预期:[>,>]

实际:['NotLoggedIn' 实例,'LoggedIn' 实例]

有趣的是,当我们交换两者时,期望测试通过...如下所示

expect: () => [
  isA<NotLoggedIn>(),
  isA<LoggedIn>(),
],

我们将不胜感激任何建议或指导。

谢谢大家

【问题讨论】:

    标签: flutter flutter-bloc


    【解决方案1】:

    如果您添加AuthLogIn 事件只是为了让您的集团为第二个事件做好准备,您可以使用blocTest 中的seed。像这样的:

    blocTest(
      'logout',
      build: () {
        when(() => mockLogout()).thenAnswer((_) async {});
        return authBloc;
      },
      seed: () => LoggedIn(),
      act: (AuthBloc bloc) {
        bloc.add(AuthLogOut());
      },
      expect: () => [
        isA<NotLoggedIn>(),
      ],
    );
    

    关于您的问题,我认为在添加两个事件之间使用延迟 (await Future.delayed(Duration(seconds: 1))) 将解决它。请注意,Bloc 默认情况下同时转换事件,在您的情况下,首先处理注销(它比登录功能完成得更快),然后处理您的登录事件,这会导致问题。

    【讨论】:

    • 非常感谢,你是个了不起的人。我最终添加了延迟并且它工作正常。我希望团队对修复感到满意。
    猜你喜欢
    • 2023-04-06
    • 1970-01-01
    • 2020-12-04
    • 2021-05-26
    • 2019-06-08
    • 2023-01-12
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    相关资源
    最近更新 更多