1

目前正在尝试为我的 cubit 实施单元测试,并且感觉严重缺乏 BLoC 在线测试文档或有用的示例。谁能解释我在设置这个测试时做错了什么。我似乎无法弄清楚问题是什么。如果有人能对我能做些什么来解决这个问题有所了解,将不胜感激。

设置状态文件:

class SettingsState extends Equatable {
  late final bool expandNavigation;
  late final bool gpsEnabled;
  late final bool celsiusEnabled;
  late final bool notificationsEnabled;
  late final bool breakingNewsNotifications;
  late final bool trendingNotifications;
  late final bool liveRemindersNotifications;
  late final bool sportsNotifications;
  SettingsState({
    required this.notificationsEnabled,
    required this.gpsEnabled,
    required this.celsiusEnabled,
    required this.expandNavigation,
    required this.breakingNewsNotifications,
    required this.trendingNotifications,
    required this.liveRemindersNotifications,
    required this.sportsNotifications,
  });
  SettingsState copyWith({
    bool? gpsEnabled,
    bool? celsiusEnabled,
    bool? expandNavigation,
    bool? notificationsEnabled,
    bool? breakingNewsNotifications,
    bool? trendingNotifications,
    bool? liveRemindersNotifications,
    bool? sportsNotifications,
  }) {
    return SettingsState(
      expandNavigation: expandNavigation ?? this.expandNavigation,
      gpsEnabled: gpsEnabled ?? this.gpsEnabled,
      celsiusEnabled: celsiusEnabled ?? this.celsiusEnabled,
      notificationsEnabled: notificationsEnabled ?? this.notificationsEnabled,
      breakingNewsNotifications:
          breakingNewsNotifications ?? this.breakingNewsNotifications,
      trendingNotifications:
          trendingNotifications ?? this.trendingNotifications,
      liveRemindersNotifications:
          liveRemindersNotifications ?? this.liveRemindersNotifications,
      sportsNotifications: sportsNotifications ?? this.sportsNotifications,
    );
  }
  // mapping user settings
  Map<String, dynamic> toMap() {
    return {
      'expandNavigation': expandNavigation,
      'gpsEnabled': gpsEnabled,
      'celsiusEnabled': celsiusEnabled,
      'notificationsEnabled': notificationsEnabled,
      'breakingNewsNotifications': breakingNewsNotifications,
      'trendingNotifications': trendingNotifications,
      'liveRemindersNotifications': liveRemindersNotifications,
      'sportsNotifications': sportsNotifications,
    };
  }
  //  grabbing settings state from map
  factory SettingsState.fromMap(Map<String, dynamic> map) {
    if (map == map['']) {
      return SettingsState(
        expandNavigation: map[''],
        gpsEnabled: map[''],
        celsiusEnabled: map[''],
        notificationsEnabled: map[''],
        breakingNewsNotifications: map[''],
        trendingNotifications: map[''],
        liveRemindersNotifications: map[''],
        sportsNotifications: map[''],
      );
    } else {
      return SettingsState(
        expandNavigation: map['expandNavigation'],
        gpsEnabled: map['gpsEnabled'],
        celsiusEnabled: map['celsiusEnabled'],
        notificationsEnabled: map['notificationsEnabled'],
        breakingNewsNotifications: map['breakingNewsNotifications'],
        trendingNotifications: map['trendingNotifications'],
        liveRemindersNotifications: map['liveRemindersNotifications'],
        sportsNotifications: map['sportsNotifications'],
      );
    }
  }
  // encode to a json
  String toJson() => json.encode(toMap());
  // decode the json
  factory SettingsState.fromJson(String source) =>
      SettingsState.fromMap(json.decode(source));
  //! Helps for equatable and unit testing
  @override
  List<Object?> get props => [
        expandNavigation,
        gpsEnabled,
        celsiusEnabled,
        notificationsEnabled,
        breakingNewsNotifications,
        trendingNotifications,
        liveRemindersNotifications,
        sportsNotifications,
      ];
  //! Shows changes in State for Bloc Observers
  @override
  String toString() => 'SettingsState(expandNavigation: $expandNavigation, '
      'gpsEnabled: $gpsEnabled, celsiusEnabled: $celsiusEnabled, notificationsEnabled: $notificationsEnabled,'
      'breakingNewsNotifications: $breakingNewsNotifications, trendingNotifications: $trendingNotifications,'
      ' liveRemindersNotifications: $liveRemindersNotifications, sportsNotifications: $sportsNotifications)';
}

设置Cubit文件:

import 'dart:convert';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
part 'settings_state.dart';
//bloc/cubit for the settings screen
class SettingsCubit extends Cubit<SettingsState> with HydratedMixin {
  SettingsCubit()
      : super(SettingsState(
          expandNavigation: false,
          gpsEnabled: false,
          celsiusEnabled: false,
          notificationsEnabled: false,
          breakingNewsNotifications: false,
          trendingNotifications: false,
          liveRemindersNotifications: false,
          sportsNotifications: false,
        ));
  // Toggle for Expanding Navigation
  void toggleExpandNavigation(bool newValue) =>
      emit(state.copyWith(expandNavigation: newValue));
  // Toggle for GPS
  void toggleGpsEnabled(bool newValue) =>
      emit(state.copyWith(gpsEnabled: newValue));
  // Toggle for Celsius or Fahrenheit
  void toggleCelsiusEnabled(bool newValue) =>
      emit(state.copyWith(celsiusEnabled: newValue));
  // Toggle for All Notifications
  void toggleNotificationsEnabled(bool newValue) {
    emit(state.copyWith(notificationsEnabled: newValue));
  }
  // Toggle for Breaking News Notifications
  void toggleBreakingNewsNotifications(bool newValue) {
    emit(state.copyWith(breakingNewsNotifications: newValue));
  }
  // Toggle for Trending Notifications
  void toggleTrendingNotifications(bool newValue) {
    emit(state.copyWith(trendingNotifications: newValue));
  }
  // Toggle for Live Reminders Notifications
  void toggleLiveRemindersNotifications(bool newValue) {
    emit(state.copyWith(liveRemindersNotifications: newValue));
  }
  // Toggle for Sports Notifications
  void toggleSportsNotifications(bool newValue) {
    emit(state.copyWith(sportsNotifications: newValue));
  }
  // retrieving from phone storage - json
  @override
  SettingsState? fromJson(Map<String, dynamic> json) {
    return SettingsState.fromMap(json);
  }
  // writing to phone storage - json
  @override
  Map<String, dynamic>? toJson(SettingsState state) {
    return state.toMap();
  }
}

BLoC 测试文件:

import 'package:bloc_test/bloc_test.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/services.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:news_test_app/logic/cubit/settings_cubit.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path_provider/path_provider.dart';
import 'package:mocktail/mocktail.dart';
class MockCubit extends Mock implements SettingsCubit {}
class MockStorage extends Mock implements Storage {}
void main() {
  TestWidgetsFlutterBinding.ensureInitialized();
  group('SettingsCubit', () {
    SettingsCubit settingsCubit = SettingsCubit();
    Storage storage;
    setUp(() {
      storage = MockStorage();
      HydratedBloc.storage = storage;
      settingsCubit = SettingsCubit();
    });
    tearDown(() {
      settingsCubit.close();
    });
    blocTest<SettingsCubit, SettingsState>(
        'the cubit should emit a SettingsState(expandNavigation: true, gpsEnabled: false, celsiusEnabled: false, notificationsEnabled: false, '
        'breakingNewsNotifications: false, trendingNotifications: false, liveRemindersNotifications: false, sportsNotifications: false) '
        'when cubit.toggleExpandNavigation is called',
        build: () => settingsCubit,
        act: (cubit) => settingsCubit.toggleExpandNavigation(true),
        expect: () => [
              settingsCubit.state,
              //settingsCubit.state,
              // SettingsState(
              //   expandNavigation: false,
              //   gpsEnabled: false,
              //   celsiusEnabled: false,
              //   notificationsEnabled: false,
              //   breakingNewsNotifications: false,
              //   trendingNotifications: false,
              //   liveRemindersNotifications: false,
              //   sportsNotifications: false,
              // ),
            ]);
  });
}

控制台输出为:

package:test_api                             expect
package:bloc_test/src/bloc_test.dart 193:9   testBloc.<fn>
===== asynchronous gap ===========================
dart:async                                   _asyncThenWrapperHelper
package:bloc_test/src/bloc_test.dart         testBloc.<fn>
dart:async                                   runZonedGuarded
package:bloc_test/src/bloc_test.dart 172:9   testBloc
package:bloc_test/src/bloc_test.dart 140:11  blocTest.<fn>
package:bloc_test/src/bloc_test.dart 139:26  blocTest.<fn>
Expected: [
            SettingsState:SettingsState(expandNavigation: false, gpsEnabled: false, celsiusEnabled: false, notificationsEnabled: false,breakingNewsNotifications: false, trendingNotifications: false, liveRemindersNotifications: false, sportsNotifications: false)
          ]
  Actual: []
   Which: at location [0] is [] which shorter than expected
4

0 回答 0