繁体   English   中英

Flutter 块测试

[英]Flutter Bloc Test

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

下面是集团本身。

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 state

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

测试失败并显示以下消息

预期:[<<“LoggedIn”实例>>,<<“NotLoggedIn”实例>>]

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

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

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

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

谢谢大家

如果您添加AuthLogIn事件只是为了为第二个事件准备您的 bloc,那么您可以使用来自blocTestseed 像这样的东西:

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默认情况下同时转换事件,在您的情况下,首先处理注销(它比登录功能完成得更快),然后处理您的登录事件,这会导致问题。

暂无
暂无

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

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