Slide 1

Slide 1 text

Write tests for Provider Hiroki Matsue (@macs_6) May 22th, 2019 Flutter Meetup Tokyo #9

Slide 2

Slide 2 text

This talk is about How to test Provider classes

Slide 3

Slide 3 text

What is Provider Google I/O 2019ͷFlutterʹ͓͚Δ࣮ફతͳstate؅ཧͷൃදͰ ঺հ͞Εͨύοέʔδ Pragmatic State Management in Flutter (Google I/O'19) https://youtu.be/d_m5csmrf7I

Slide 4

Slide 4 text

A dependency injection system built with widgets for widgets. provider is mostly syntax sugar for InheritedWidget, to make common use-cases straightforward. https://github.com/rrousselGit/provider • ΄΅InheritedWidgetͷγϯλοΫεγϡΨʔ • BLoCΛ࢖͏࣌ʹ΋ࣗલͰProvider૬౰ͷ΋ͷΛ࣮૷͍ͯͨ͠ ͸ͣ

Slide 5

Slide 5 text

BLoC޲͚ʹॻ͍͍ͯͨInheritedWidgetΛ࢖ͬͨProvider class CartProvider extends InheritedWidget { final CartBloc cartBloc; CartProvider({ Key key, CartBloc cartBloc, Widget child, }) : cartBloc = cartBloc ?? CartBloc(), super(key: key, child: child); @override bool updateShouldNotify(InheritedWidget oldWidget) => true; static CartBloc of(BuildContext context) => (context.inheritFromWidgetOfExactType(CartProvider) as CartProvider) .cartBloc; } final cartBloc = CartProvider.of(context); https://github.com/filiph/stateexperiments/blob/19c321bbc62ac10855751124e3ea9701e583d6ea/shared/lib/src/bloc/cartprovider.dart

Slide 6

Slide 6 text

ProviderύοέʔδΛ࢖͏ͱ͜͏ͳΔ Provider( builder: (_) => ExampleBloc(), dispose: (_, value) => value.dispose(), child: ExampleBloc(), ); final bloc = Provider.of(context)

Slide 7

Slide 7 text

શ෦BLoCͰॻͭ͘΋ΓͳΒbloc_providerύοέʔδ bloc is disposed automatically https://pub.dev/packages/bloc_provider BlocProvider( creator: (_context, _bag) => ExampleBloc(), child: Example(), )

Slide 8

Slide 8 text

ProviderΛ࢖͏ͱ • stream΍RxDartΛ࢖Θͣʹෳ਺WidgetؒͷstateΛ؅ཧͰ͖ ֶͯशίετ͕௿͍ • ඞཁʹԠͯ͡BLoC΋ಋೖͰ͖Δ

Slide 9

Slide 9 text

How to write tests?

Slide 10

Slide 10 text

class Counter with ChangeNotifier { Counter( this._number, ); factory Counter.withInitialValues({ int number = 0, }) { return Counter(number); } int _number; int get number => _number; void increment() { _number++; notifyListeners(); } }

Slide 11

Slide 11 text

notifyListeners()Λແࢹ͢ΔͳΒ test('increment', () { final counter = Counter.withInitialValues(); expect(counter.number, 0); counter.increment(); expect(counter.number, 1); });

Slide 12

Slide 12 text

֤छύοέʔδͷςετͰ͸testWidgetsΛ࢖͍ͬͯΔ

Slide 13

Slide 13 text

UIςετͱ͸෼཭ͯ͠ widgetΛςετ޲͚ʹॳظԽ͢Δ

Slide 14

Slide 14 text

testWidgets("increment", (tester) async { final key = GlobalKey(); await tester.pumpWidget( ChangeNotifierProvider( builder: (context) => Counter.withInitialValues(), child: MaterialApp( home: Consumer( builder: (context, counter, child) => FlatButton( key: key, onPressed: () => counter.increment(), child: Text(counter.number.toString())), ), ), ), ); expect(find.text('0'), findsOneWidget); expect(find.text('1'), findsNothing); await tester.tap(find.byKey(key)); await tester.pumpAndSettle(); expect(find.text('0'), findsNothing); expect(find.text('1'), findsOneWidget); });

Slide 15

Slide 15 text

֤छύοέʔδͷςετͰݟΒΕΔ޻෉

Slide 16

Slide 16 text

࢖͍ճ͢widgetΛอଘ͓ͯ͘͠ final tree = ChangeNotifierProvider( builder: (context) => Counter.withInitialValues(), child: MaterialApp( home: Consumer( builder: (context, counter, child) => FlatButton( key: key, onPressed: () => counter.increment(), child: Text(counter.number.toString())), ), ), );

Slide 17

Slide 17 text

஋ʹରͯ͠௚઀ݕূΛߦ͏ testWidgets("increment", (tester) async { final key = GlobalKey(); int number; await tester.pumpWidget( ChangeNotifierProvider( builder: (context) => Counter.withInitialValues(), child: MaterialApp( home: Consumer(builder: (context, counter, child) { number = counter.number; return FlatButton( key: key, onPressed: () => counter.increment(), child: Container(), ); }), ), ), ); });

Slide 18

Slide 18 text

notifierΛcontext͔Βऔಘͯ͠ݕূ͢Δ testWidgets('works with MultiProvider', (tester) async { final key = GlobalKey(); var notifier = ChangeNotifier(); await tester.pumpWidget(MultiProvider( providers: [ ChangeNotifierProvider.value(notifier: notifier), ], child: Container(key: key), )); expect(Provider.of(key.currentContext), notifier); }); https://github.com/rrousselGit/provider/blob/fe778651565f7563dc4a1b2afb513119c5424761/test/changenotifierprovider_test.dart#L11-

Slide 19

Slide 19 text

·ͱΊ • testWidgets Λ࢖ͬͯςετ͸ॻ͘ • ֤छύοέʔδΛݟΔͱςετͷهड़ΛݮΒ͢޻෉͕৭ʑݟ ΒΕΔ • ର৅ͷwidgetΛ࢖͍ճ͢ • ม਺ʹೖΕͯݕূ͢Δ • notifierΛऔಘ͢Δ

Slide 20

Slide 20 text

References • Developer Questͷςετ: https://github.com/2d-inc/ developerquest/blob/master/test/worldtest.dart • Providerύοέʔδͷςετ: https://github.com/ rrousselGit/provider/blob/ fe778651565f7563dc4a1b2afb513119c5424761/test/ changenotifierprovider_test.dart • FlutterຊମͷChangeNotifierςετ: https://github.com/ flutter/flutter/blob/

Slide 21

Slide 21 text

Thanks