fluttercommunity / get_it

Get It - Simple direct Service Locator that allows to decouple the interface from a concrete implementation and to access the concrete implementation from everywhere in your App. Maintainer: @escamoteur
https://pub.dev/packages/get_it
MIT License
1.36k stars 149 forks source link

Error Register SharedPreferences in Widget Testing #314

Closed rrifafauzikomara closed 1 year ago

rrifafauzikomara commented 1 year ago

Hi, I get this error when register SharedPreferences class.

dart:async                                                        _Completer.completeError
package:shared_preferences/shared_preferences.dart 38:19          SharedPreferences.getInstance
===== asynchronous gap ===========================
dart:async                                                        _CustomZone.registerBinaryCallback
package:shared_preferences/shared_preferences.dart 33:13          SharedPreferences.getInstance
test/presentation/ui/profile/main_profile_screen_test.dart 20:51  main.<fn>.<fn>

PlatformException(channel-error, Unable to establish connection on channel., null, null)

This is my widget testing.

final sl = GetIt.instance;
void main() {
  group('MainProfileScreen test', () {
    late AppTestMaterialApp app;

    setUpAll(() async {
      TestWidgetsFlutterBinding.ensureInitialized();
      final preferences = await SharedPreferences.getInstance();
      sl.registerLazySingleton(() => preferences);

      ...

      app = AppTestMaterialApp(
        providers: [
          BlocProvider(
            create: (context) => ProfileBloc(
              profileUseCase: sl(),
              authUseCase: sl(),
              localization: sl(),
            ),
          ),
        ],
        home: const MainProfileScreen(),
      );
    });

    testWidgets('can render MainProfileScreen', (WidgetTester tester) async {
      await tester.pumpWidget(app.widget);
      await tester.pumpAndSettle();

      expect(find.byType(MainProfileScreen), findsOneWidget);
    });
  });

  tearDownAll(() {
    /// clear di after finish test
    sl.reset(dispose: true);
  });
}
emintolgahanpolat commented 1 year ago

https://github.com/flutter/packages/blob/main/packages/shared_preferences/shared_preferences/test/shared_preferences_test.dart

You must create a mock platform for shared preference testing. Your problem is not about get_it.

vousmeevoyez commented 1 year ago

You need to create mock for shared preference.


import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'storage_test.mocks.dart'; // change depending on your test_file_name and generate it from bulid_runner

final sl = GetIt.instance;

@GenerateMocks([SharedPreferences])
void main() {
  group('MainProfileScreen test', () {
    late MockSharedPreferences mockSharedPreferences;
    late AppTestMaterialApp app;

    setUpAll(() async {
      TestWidgetsFlutterBinding.ensureInitialized();

       mockSharedPreferences = MockSharedPreferences();
      sl.registerLazySingleton(() => mockSharedPreferences);

      ...

      app = AppTestMaterialApp(
        providers: [
          BlocProvider(
            create: (context) => ProfileBloc(
              profileUseCase: sl(),
              authUseCase: sl(),
              localization: sl(),
            ),
          ),
        ],
        home: const MainProfileScreen(),
      );
    });

    testWidgets('can render MainProfileScreen', (WidgetTester tester) async {
       when(mockSharedPreferences.getString(any)).thenAnswer((_) => "hello");

      await tester.pumpWidget(app.widget);
      await tester.pumpAndSettle();

      expect(find.byType(MainProfileScreen), findsOneWidget);
    });
  });

  tearDownAll(() {
    /// clear di after finish test
    sl.reset(dispose: true);
  });
}
vousmeevoyez commented 1 year ago

You need to create mock for shared preference.

import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'storage_test.mocks.dart'; // change depending on your test_file_name and generate it from bulid_runner

final sl = GetIt.instance;

@GenerateMocks([SharedPreferences])
void main() {
  group('MainProfileScreen test', () {
    late MockSharedPreferences mockSharedPreferences;
    late AppTestMaterialApp app;

    setUpAll(() async {
      TestWidgetsFlutterBinding.ensureInitialized();

       mockSharedPreferences = MockSharedPreferences();
      sl.registerLazySingleton(() => mockSharedPreferences);

      ...

      app = AppTestMaterialApp(
        providers: [
          BlocProvider(
            create: (context) => ProfileBloc(
              profileUseCase: sl(),
              authUseCase: sl(),
              localization: sl(),
            ),
          ),
        ],
        home: const MainProfileScreen(),
      );
    });

    testWidgets('can render MainProfileScreen', (WidgetTester tester) async {
       when(mockSharedPreferences.getString(any)).thenAnswer((_) => "hello");

      await tester.pumpWidget(app.widget);
      await tester.pumpAndSettle();

      expect(find.byType(MainProfileScreen), findsOneWidget);
    });
  });

  tearDownAll(() {
    /// clear di after finish test
    sl.reset(dispose: true);
  });
}

@rrifafauzikomara

escamoteur commented 1 year ago

Thanks guys for replying