Jesway / flutter_translate

Flutter Translate is a fully featured localization / internationalization (i18n) library for Flutter.
MIT License
403 stars 118 forks source link

How to mock the library in widget tests? #48

Closed VytorCalixto closed 4 years ago

VytorCalixto commented 4 years ago

When testing a widget the _translations map is passed as null and throws a exception. It's possible to wrap the widget in a LocalizedApp widget and configure the localization, but I believe that testing a single widget should be more straightforward. Am I missing something here?

Example error:

The following NoSuchMethodError was thrown building ExpiredProductButton(dirty):
The method 'containsKey' was called on null.
Receiver: null
Tried calling: containsKey("mission")
xzhorikx commented 4 years ago

I've just spent two hours configuring all the required things, but I've made the following approach:

  1. Create a simple service class that would have a transaltion method (i.e. String safeTranslate(String key)).
  2. Use DI/Service Locator to get said service in class
  3. Call safeTranslate(key) every time I need a translation

Example:

  1. Creating TranslateService

I use get_it and injectable as a service locator in my app.

import 'package:flutter_translate/flutter_translate.dart' as globalTranslate;
import 'package:injectable/injectable.dart';

/// Implementation that is registered in GetIt service locator
@RegisterAs(TranslateService)
@injectable
class TranslateServiceImpl implements TranslateService {
  @override
  String safeTranslate(String key) {
    try{
      return globalTranslate.translate(key);
    } catch(Exception){
      return "translation.error";
    }
  }
}

/// Abstract translate service
abstract class TranslateService {
  String safeTranslate(String key);
}
  1. Use DI/Service locator in tested class

At this point, you need to configure GetIt - go through their tutorials on pages linked above and all should be safe and sound. Two notes that are not mentioned in tutorials:

import 'package:get_it/get_it.dart';
...

/// Class that will be tested
class TestedClass {
  /// Instance of TranslateService that is provided by GetIt (service locator)
  final TranslateService _translateService = GetIt.instance.get();

  // Some method that uses translation
  String doSomeStuff() {
    return _translateService.safeTranslate("translation_key")
  }
}
  1. Testing a class that requires translation

void main() {

configureInjection("Some env value");

FlutterTest.test("Date formatter: today date", (){ /// Translation service should be located once class is created final TestedClass testedClass = TestedClass(); String safeTranslation = testedClass.doSomeStuff(); <--- no exception here ... });

IlyaMax commented 3 years ago

@VytorCalixto you can call Localization.load(<String,dynamic>{}); before tests and error won't be thrown