Proper way of using DI (injectable-getIt) for testing in flutter?

1.7k views Asked by At

Is it fine to get instances from getIt initialised in lib(dev) code or should I use another way, or another DI setup for tests?

Please refer the code below:

 void main() {
      TravellerProfileViewModel travellerProfileViewModel;
      UserService mockUserService;
      setUpAll(() {
        // CoreInjector is initialised in lib, and gives the getIt instance
        CoreInjector.initialize();
        //register mockUserService in place of actual user service in the CoreInjector.getIt
        mockUserService = registerAndGetMock<UserService>(MockUserService());
        // CoreInjector gives TravellerProfileViewModel, injected with UserService
        travellerProfileViewModel =
            CoreInjector.getIt.get<TravellerProfileViewModel>();
      });
}

T registerAndGetMock<T>(T mockAble) {
  _removeRegistrationIfExists<T>();
  CoreInjector.getIt.registerFactory<T>(() => mockAble);
  return mockAble;
}

CoreInjector Code

class CoreInjector {
  static GetIt _getIt;

  static GetIt get getIt => _getIt;

  static void initialize() {
    _getIt ??= _configureInjection();
  }
}
@InjectableInit(preferRelativeImports: false)
GetIt _configureInjection() =>
    $initGetIt(GetIt.asNewInstance());

The TravellerProfileViewModel has a dependency on a Service, which is injected under the hood through the same CoreInjector.

Also is it fine to have constructor injections, or should I make my constructor params optional? What is the better way, among the two below?

@injectable
class TravellerProfileViewModel extends BaseViewModel {
  final UserService _userService;
  //injected by DI under the hood    
  TravellerProfileViewModel(this._userService);
}

Injectable generated code:

GetIt $initGetIt(
  GetIt get, {
  String environment,
  EnvironmentFilter environmentFilter,
}) {
  final gh = GetItHelper(get, environment, environmentFilter);
  gh.factory<UserService>(() => UserService());
  gh.factory<TravellerProfileViewModel>(
      () => TravellerProfileViewModel(get<UserService>()));
  return get;
}

or

   @injectable
    class TravellerProfileViewModel extends BaseViewModel {
      UserService _userService;
      //injected by DI under the hood, also gives liberty to pass optional params in case of 
        testing
      TravellerProfileViewModel({UserService userService}){
             _userService = userService?? CoreInjector.getIt.get<UserService>();
      }
    }

Injectable generated code:

GetIt $initGetIt(
  GetIt get, {
  String environment,
  EnvironmentFilter environmentFilter,
}) {
  final gh = GetItHelper(get, environment, environmentFilter);
  gh.factory<UserService>(() => UserService());
  gh.factory<TravellerProfileViewModel>(
      () => TravellerProfileViewModel(userService: get<UserService>()));
  return get;
}
0

There are 0 answers