Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Flutter+Providerでウィジェットのテストを書く/widget-test-with...
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Osamtimizer
August 07, 2020
Programming
1.9k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Flutter+Providerでウィジェットのテストを書く/widget-test-with-provider
Osamtimizer
August 07, 2020
More Decks by Osamtimizer
See All by Osamtimizer
SUZURIにおけるSREの取り組み/SRE-and-SUZURI
osamtimizer
0
1.4k
suzuri-data-driven-2020
osamtimizer
1
1.7k
pepabo-with-flutter-2020
osamtimizer
1
2.4k
SUZURIのAndroidアプリをFlutterで作っている話 / SUZURI-meets-Flutter
osamtimizer
2
23k
RubyのOSSコードリーディング / ruby-oss-code-reading
osamtimizer
4
3.3k
Other Decks in Programming
See All in Programming
「人を評価する AI」の設計と実装
ryoyanara
0
220
AI Engineeringは、AIプロダクトだけのものか? 〜AIがソフトウェアを作る時代の新しい当たり前〜 / No AI in your product. AI Engineering in your development.
rkaga
5
500
jsmini JavaScript Engine を作ってみた話
yosuke_furukawa
PRO
0
350
2年かけて Deno に DOMMatrix を実装した話 / How I implemented DOMMatrix in Deno over two years
petamoriken
0
220
in-process GraphQL のすすめ #ginzajs
izumin5210
4
1.4k
Android CLI
fornewid
0
230
仕様駆動開発へのトライを機に チームに適合する手法を模索し続けている話
freee
PRO
0
590
自動化したのに回らないテスト運用の壁ーAI時代の品質責任と生産性
mfunaki
1
150
AI Readyの正体はデータマネジメントだ メダリオン2.0の最前線
freee
PRO
0
350
Go を使い始めて 2 ヶ月の学び / My first two months with Go
contour_gara
0
350
全PRの83%がAIレビューだけでマージできるようになった開発組織はその後どうなったか
athug
1
1.9k
React本体のコードリーディング
high_g_engineer
1
150
Featured
See All Featured
30 Presentation Tips
portentint
PRO
1
370
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
500
Agile that works and the tools we love
rasmusluckow
331
22k
GitHub's CSS Performance
jonrohan
1033
470k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
Between Models and Reality
mayunak
4
400
A designer walks into a library…
pauljervisheath
211
24k
Code Reviewing Like a Champion
maltzj
528
40k
It's Worth the Effort
3n
188
29k
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
Designing for Performance
lara
611
70k
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
1
6.1k
Transcript
࣌ాཧ(.01FQBCP *OD %BSU.FFUVQ0TBLB 'MVUUFS 1SPWJEFSͰ ΟδΣοτͷςετΛॻ͘
ϞόΠϧ8FCΞϓϦέʔγϣϯΤϯδχΞ ࣌ాཧ!PTBNUJNJ[FS 46;63*ࣄۀ෦ϓϩμΫτνʔϜ IUUQTPTBNUJNJ[FSIBUFOBCMPHDPN
None
ΦϦδφϧάοζ͕࡞ΕΔɺചΕΔɺങ͑Δɻ ը૾Λ1ຕΞοϓ ͢Δ͚ͩ ࣗಈతʹ͕ Ͱ͖·͢ ࣗͰങ͑Δ͠ ചΔ͜ͱͰ͖·͢
None
None
͡Ίʹ wࢿྉޙ΄ͲΠϯλʔωοτ্Ͱެ։͠·͢ wIUUQTTQFBLFSEFDLDPNPTBNUJNJ[FS
ࠓ͢͜ͱ w'MVUUFSͷ8JEHFU5FTU w1SPWJEFSʹґଘͨ͠ΟδΣοτͷ8JEHFU5FTUΛॻ͘ w·ͱΊ
8JEHFU5FTU
ΟδΣοτʹର͢Δςετ
'MVUUFSʹ͓͚Δςετ w6OJU5FTU୯ҰͷϝιουΫϥεʹର͢Δςετ w*OUFHSBUJPO5FTUΞϓϦશମʹର͢Δςετ w8JEHFU5FTU୯ҰͷΟδΣοτʹର͢Δςετ
'MVUUFSʹ͓͚Δςετ w6OJU5FTU୯ҰͷϝιουΫϥεʹର͢Δςετ w*OUFHSBUJPO5FTUΞϓϦશମʹର͢Δςετ w8JEHFU5FTU୯ҰͷΟδΣοτʹର͢Δςετ
ΟδΣοτͷԿΛ ςετ͢Δʁ
ΟδΣοτͷ ݟͨͱڍಈ
8JEHFU5FTU͕Χόʔ͢Δͷ wΟδΣοτએݴతʹهड़ ˠঢ়ଶΛ༩͑ͨͱ͖ɺఆͨ͠ݟͨʹͳΔ͔ʁ wϢʔβʔͷೖྗΠϕϯτͳͲΛड͚ͯԿ͔Λ͢ΔΟδΣοτ͋Δ ˠΠϕϯτ͕ൃՐͨ͠ͱ͖ɺఆͨ͠ڍಈΛ͢Δ͔ʁ
8JEHFU5FTUΛॻ͍ͯΈΔ void main() { testWidgets('MyWidget has a title and message',
(WidgetTester tester) async { // ςετͷ४උ await tester.pumpWidget(MyWidget(title: 'T', message: 'M')); // ΟδΣοτͷ୳ࡧ final titleFinder = find.text('T'); final messageFinder = find.text('M'); // ϚονϟͰΟδΣοτΛݕূ expect(titleFinder, findsOneWidget); expect(messageFinder, findsOneWidget); }); } ࢀߟIUUQTqVUUFSEFWEPDTDPPLCPPLUFTUJOHXJEHFUJOUSPEVDUJPO
8JEHFU5FTUΛॻ͍ͯΈΔ void main() { testWidgets('MyWidget has a title and message',
(WidgetTester tester) async { // ςετͷ४උ await tester.pumpWidget(MyWidget(title: 'T', message: 'M')); // ΟδΣοτͷ୳ࡧ final titleFinder = find.text('T'); final messageFinder = find.text('M'); // ϚονϟͰΟδΣοτΛݕূ expect(titleFinder, findsOneWidget); expect(messageFinder, findsOneWidget); }); } ࢀߟIUUQTqVUUFSEFWEPDTDPPLCPPLUFTUJOHXJEHFUJOUSPEVDUJPO
8JEHFU5FTUΛॻ͍ͯΈΔ void main() { testWidgets('MyWidget has a title and message',
(WidgetTester tester) async { // ςετͷ४උ await tester.pumpWidget(MyWidget(title: 'T', message: 'M')); // ΟδΣοτͷ୳ࡧ final titleFinder = find.text('T'); final messageFinder = find.text('M'); // ϚονϟͰΟδΣοτΛݕূ expect(titleFinder, findsOneWidget); expect(messageFinder, findsOneWidget); }); } ࢀߟIUUQTqVUUFSEFWEPDTDPPLCPPLUFTUJOHXJEHFUJOUSPEVDUJPO
8JEHFU5FTUΛॻ͍ͯΈΔ void main() { testWidgets('MyWidget has a title and message',
(WidgetTester tester) async { // ςετͷ४උ await tester.pumpWidget(MyWidget(title: 'T', message: 'M')); // ΟδΣοτͷ୳ࡧ final titleFinder = find.text('T'); final messageFinder = find.text('M'); // ϚονϟͰΟδΣοτΛݕূ expect(titleFinder, findsOneWidget); expect(messageFinder, findsOneWidget); }); } ࢀߟIUUQTqVUUFSEFWEPDTDPPLCPPLUFTUJOHXJEHFUJOUSPEVDUJPO
8JEHFU5FTUΛॻ͍ͯΈΔ void main() { testWidgets('Add and remove a todo', (WidgetTester
tester) async { await tester.pumpWidget(TodoList()); // WidgetTesterܦ༝ͰΟδΣοτΛૢ࡞ await tester.enterText(find.byType(TextField), 'hi'); await tester.tap(find.byType(FloatingActionButton)); // ΟδΣοτΛϦϏϧυ await tester.pump(); expect(find.text('hi'), findsOneWidget); await tester.drag(find.byType(Dismissible), Offset(500.0, 0.0)); await tester.pumpAndSettle(); expect(find.text('hi'), findsNothing); }); } ࢀߟIUUQTqVUUFSEFWEPDTDPPLCPPLUFTUJOHXJEHFUJOUSPEVDUJPO
8JEHFU5FTUΛॻ͍ͯΈΔ void main() { testWidgets('Add and remove a todo', (WidgetTester
tester) async { await tester.pumpWidget(TodoList()); // WidgetTesterܦ༝ͰΟδΣοτΛૢ࡞ await tester.enterText(find.byType(TextField), 'hi'); await tester.tap(find.byType(FloatingActionButton)); // ΟδΣοτΛϦϏϧυ await tester.pump(); expect(find.text('hi'), findsOneWidget); await tester.drag(find.byType(Dismissible), Offset(500.0, 0.0)); await tester.pumpAndSettle(); expect(find.text('hi'), findsNothing); }); } ࢀߟIUUQTqVUUFSEFWEPDTDPPLCPPLUFTUJOHXJEHFUJOUSPEVDUJPO
8JEHFU5FTUΛॻ͍ͯΈΔ void main() { testWidgets('Add and remove a todo', (WidgetTester
tester) async { await tester.pumpWidget(TodoList()); // WidgetTesterܦ༝ͰΟδΣοτΛૢ࡞ await tester.enterText(find.byType(TextField), 'hi'); await tester.tap(find.byType(FloatingActionButton)); // ΟδΣοτΛϦϏϧυ await tester.pump(); expect(find.text('hi'), findsOneWidget); await tester.drag(find.byType(Dismissible), Offset(500.0, 0.0)); await tester.pumpAndSettle(); expect(find.text('hi'), findsNothing); }); } ࢀߟIUUQTqVUUFSEFWEPDTDPPLCPPLUFTUJOHXJEHFUJOUSPEVDUJPO
8JEHFU5FTUͷ࣮ߦ $ flutter test 00:05 +1: All tests passed! ࢀߟIUUQTqVUUFSEFWEPDTDPPLCPPLUFTUJOHXJEHFUJOUSPEVDUJPO
8JEHFU5FTU wݕূ͍ͨ͠ΟδΣοτΛ5FTUFSʹ͢ wίʔυʹΑͬͯΟδΣοτΛૢ࡞ͯ͠ݕূ wཁૉ͕ଘࡏ͢Δ͔ wΠϕϯτൃՐ࣌ʹఆͨ͠ڍಈʹͳΔ͔
8JEHFU5FTUͷࠔΓͲ͜Ζ w6OJU5FTUͱൺֱ͢Δͱɺมߋʹऑ͍ w6*ͦͦมߋ͞Ε͍͢ wςετͳΔ͘$*Ͱࣗಈ࣮ߦ͍ͤͨ͞ w͋·Γڽͬͨ8JEHFU5FTUΛॻ͖͗͢Δͱɺςετͷमਖ਼ʹΘΕΔ
1SPWJEFSʹґଘͨ͠ ΟδΣοτͷςετ
1SPWJEFSʹґଘͨ͠ΟδΣοτͷςετ w1SPWJEFS w'MVUUFSͰͷঢ়ଶཧΛ͘͢͢͠Δύοέʔδ wґଘ͍ͯ͠ΔΟδΣοτͷ8JEHFU5FTUʹ͕ඞཁ w͔͠͠ɺϝϦοτ͋Δ
αϯϓϧΞϓϦ
ˠ
αϯϓϧΞϓϦ wϝʔϧΞϓϦ wΞϓϦΛىಈ͢Δͱ࠷৽ͷϝʔϧΛऔಘͯ͠දࣔ wϦετΛλοϓ͢Δͱϝʔϧͷৄࡉը໘ʹϓογϡભҠ
αϯϓϧΞϓϦ .BUFSJBM"QQ )PNF 4DB⒎PME .BJM-JTU -JTU5JMF 1SPWJEFS -JTU5JMF -JTU5JMF
αϯϓϧΞϓϦ .BUFSJBM"QQ )PNF 4DB⒎PME .BJM-JTU -JTU5JMF 1SPWJEFS -JTU5JMF -JTU5JMF
αϯϓϧΞϓϦ class MailList extends StatefulWidget { … } class _MailListState
extends State<MailList> { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { // initStateྃޙʹϝʔϧΛऔಘ͢ΔΞΫγϣϯΛൃߦ context.read<MailStore>().fetchMails(); }); } …
αϯϓϧΞϓϦ class MailList extends StatefulWidget { … } class _MailListState
extends State<MailList> { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { // initStateྃޙʹϝʔϧΛऔಘ͢ΔΞΫγϣϯΛൃߦ context.read<MailStore>().fetchMails(); }); } …
αϯϓϧΞϓϦ Widget build(BuildContext context) { // Providerܦ༝Ͱද͖ࣔ͢ϝʔϧҰཡΛऔಘ final mails =
context.watch<MailStore>().mails; return Container( child: ListView.builder( itemBuilder: (context, index) { return ListTile( … onTap: () async { // ListTileλοϓ࣌ʹϝʔϧৄࡉʹભҠ Navigator.of(context).pushNamed( MailDetail.routeName, arguments: mails[index], );
αϯϓϧΞϓϦͰςετ͍ͨ͠ϙΠϯτ wΟδΣοτͷॳճϏϧυ࣌ʹϦΫΤετΛ࣮ߦͯ͠ϝʔϧΛऔಘ wϝʔϧΛλοϓ͢Δͱɺͦͷϝʔϧͷৄࡉը໘ભҠ
αϯϓϧΞϓϦͰςετ͍ͨ͠ϙΠϯτ wΟδΣοτͷॳճϏϧυ࣌ʹϦΫΤετΛ࣮ߦͯ͠ϝʔϧΛऔಘ wϝʔϧΛλοϓ͢Δͱɺͦͷϝʔϧͷৄࡉը໘ભҠ
αϯϓϧΞϓϦͷ8JEHFU5FTU void main() { testWidgets("initialization", (WidgetTester tester) async { //ςετ༻ͷStoreΛ༻ҙ
final store = MailStore(); expect(store.mails.length, 0); await tester.pumpWidget( // testerʹ͢ΟδΣοτΛProviderͰϥοϓ ChangeNotifierProvider.value( value: store, child: Home(), ), ); // Storeͷঢ়ଶΛݕূ expect(store.mails.length, 20);
αϯϓϧΞϓϦͷ8JEHFU5FTU void main() { testWidgets("initialization", (WidgetTester tester) async { //ςετ༻ͷStoreΛ༻ҙ
final store = MailStore(); expect(store.mails.length, 0); await tester.pumpWidget( // testerʹ͢ΟδΣοτΛProviderͰϥοϓ ChangeNotifierProvider.value( value: store, child: Home(), ), ); // Storeͷঢ়ଶΛݕূ expect(store.mails.length, 20);
αϯϓϧΞϓϦͷ8JEHFU5FTU void main() { testWidgets("initialization", (WidgetTester tester) async { //ςετ༻ͷStoreΛ༻ҙ
final store = MailStore(); expect(store.mails.length, 0); await tester.pumpWidget( // testerʹ͢ΟδΣοτΛProviderͰϥοϓ ChangeNotifierProvider.value( value: store, child: Home(), ), ); // Storeͷঢ়ଶΛݕূ expect(store.mails.length, 20);
αϯϓϧΞϓϦͷ8JEHFU5FTU void main() { testWidgets("initialization", (WidgetTester tester) async { //ςετ༻ͷStoreΛ༻ҙ
final store = MailStore(); expect(store.mails.length, 0); await tester.pumpWidget( // testerʹ͢ΟδΣοτΛProviderͰϥοϓ ChangeNotifierProvider.value( value: store, child: Home(), ), ); // Storeͷঢ়ଶΛݕূ expect(store.mails.length, 20);
1SPWJEFSΛ͏8JEHFU5FTU wςετͷର6*Ͱͳ͘ɺΟδΣοτͷৼΔ͍ w௨ৗͷ8JEHFU5FTUͱൺֱ͢Δͱɺมߋʹڧ͍ wςετΛॻ͘ෛՙΛ͑ͭͭɺมߋʹڧ͍ΞϓϦΛ࡞Γ͘͢ͳΔ
·ͱΊ w8JEHFU5FTU໊લͷ௨ΓΟδΣοτʹର͢Δςετ wίʔυͰΟδΣοτͷૢ࡞Λهड़Ͱ͖Δ wมߋʹऑ͍͕ɺ1SPWJEFSͱΈ߹ΘͤΔͱৼΔ͍ͷςετ͕Ͱ͖Δ wৼΔ͍ͷςετมߋʹڧ͍