3

I want to use Provider to inject dependencies into my Flutter app.

I inject a 'repository' class which calls asynchronous native methods.

For testing purposes I want to inject a mock version of the repository.

How does one do this?

In the application code:

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => Repository()),
      ],
      child: MyApp(),
    ),
  );
}

In the test:

await tester.pumpWidget(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => Repository()),
      ],
      child: MyApp(),
    ));

Whilst the app runs fine, the test fails with the same message as when I omit the provider and just call

tester.pumpWidget(MyApp());

The Exception is:

The following ProviderNotFoundException was thrown building MyHomePage(dirty, state: _MyHomePageState#9407e): Error: Could not find the correct Provider above this MyHomePage Widget ...

main.dart:

import 'package:flutter/material.dart';
import 'repository.dart';
import 'package:provider/provider.dart';


void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => Repository()),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _days = "0";

  @override
  Widget build(BuildContext buildContext) {
  
    final _daysFuture = context.watch<Repository>().daysInSummer();
    return Material(
        child: FutureBuilder(
            future: _daysFuture,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                _days = snapshot.data;
                return Scaffold(
                  appBar: AppBar(
                    title: Text(widget.title),
                  ),
                  body: Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Text(
                          'demo text',
                        ),
                        Text(
                          "$_days",
                          style: Theme.of(context).textTheme.headline2,
                        ),
                      ],
                    ),
                  ),
                  floatingActionButton: FloatingActionButton(
                    onPressed: () {
                      context.read<Repository>().addDayInSummer();
                    },
                    tooltip: 'Increment',
                    child: Icon(Icons.add),
                  ), 
                );
              } else {
                return Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Text('Waiting for initialisation'),
                    SizedBox(
                      height: 16,
                    ),
                    CircularProgressIndicator(),
                  ],
                );
              }
            }));
  }
}

widget_test.dart:

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:summer/main.dart';

class Repository with ChangeNotifier {
  int days = 0;

  @override
  Future<String> addDayInSummer() {
    days++;
    notifyListeners();
    return daysInSummer();
  }

  @override
  Future<String> daysInSummer() {
    Future<String> s = Future.delayed(
      Duration(milliseconds: 2),
      () => days.toString(),
    );
    notifyListeners();
    return s;
  }
}

void main() {
  testWidgets('Counter increments smoke test', (WidgetTester tester) async {
    
    await tester.pumpWidget(MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => Repository()),
      ],
      child: MyApp(),
    ));

    // Verify that our counter starts at 0.
    expect(find.text('0/90'), findsOneWidget);
    expect(find.text('1/90'), findsNothing);

    //Tap the '+' icon and trigger a frame.
    await tester.tap(find.byIcon(Icons.add));
    await tester.pump();

    // Verify that our counter has incremented.
    expect(find.text('0/90'), findsNothing);
    expect(find.text('1/90'), findsOneWidget);
  });
}

Ron
  • 31
  • 3

0 Answers0