mardi 3 novembre 2020

Unit test with GetIt

I was reading through the GetIt pkg documentation on Unit testing and I am not sure what they mean by: Register all the Objects you need inside your unit Tests so that GetIt can provide its objects to the objects that you are testing.. How can you do that since you have to work with mocks and the services expect real objects?

I setup an instance of GetIt in main() and register the WebApi there. In my model I have the following:

class ActiveExamsModel with ChangeNotifier {
  var _webApi = getIt<WebApi>();

  loadData() async {
    _activeExams = await _webApi.fetchExams();
    notifyListeners();
  }
}

My model is returned by the build method of the ActiveExams widget.

@override
  Widget build(BuildContext context) {
    return ViewModelBuilder<ActiveExamsModel>.reactive(
      viewModelBuilder: () => ActiveExamsModel(),
      onModelReady: (model) => model.loadData(),
      builder: (context, model, _) => ....

How I could possibly modify this test so the widget knows it needs the WebApiMock in the model?

final activeExams = ActiveExams();

  testWidgets('Displays exams', (WidgetTester tester) async {
    await tester.pumpWidget(MaterialApp(home: activeExams));

    var examFinder = find.byType(ExamGridItem, skipOffstage: false);
    expect(examFinder, findsNWidgets(examMocks.length));
  });

My solution was to make WebApiMock inherit from WebApi and override the fetchData method to return mocks, the test is as follows:

testWidgets('Displays exams', (WidgetTester tester) async {
    GetIt.instance.registerSingleton<WebApi>(WebApiMock());
    final activeExams = ActiveExams();
    await tester.pumpWidget(MaterialApp(home: activeExams));

    var examFinder = find.byType(ExamGridItem, skipOffstage: false);
    expect(examFinder, findsNWidgets(examMocks.length));
  });
class WebApiMock extends WebApi{
  @override
  Future<List<ExamInformation>> fetchExams() =>
      Future.delayed(Duration(seconds: 1), () => examMocks);
}

But this will throw an error which complains that _activeExams is null as a result of the fetch.

The following NoSuchMethodError was thrown building Consumer(dirty, dependencies: [_InheritedProviderScope]): The method 'map' was called on null. Receiver: null Tried calling: map(Closure: (ExamInformation) => Provider) The relevant error-causing widget was: Consumer<ActiveExamsModel>

Aucun commentaire:

Enregistrer un commentaire