Save 37% off PRO during our Black Friday Sale! »

テストの可読性を支える技術

Cdcce9978fa7f10f36b021ac75da294e?s=47 ashdik
October 23, 2021
4.1k

 テストの可読性を支える技術

テストの可読性は、とても大事です。
そんな可読性をあげてくれるパッケージや考え方などを解説したので
ぜひご覧いただければ幸いです。

Cdcce9978fa7f10f36b021ac75da294e?s=128

ashdik

October 23, 2021
Tweet

Transcript

  1. ே೔େथ ςετͷՄಡੑ Λࢧ͑Δٕज़

  2. ே೔େथ 5XJUUFSɿ!EBJLJ 'MVUUFSྺɿ೥ ϒϩάɿIUUQTCMPHEBMUNF

  3. ໨࣍ w ςετ΋Մಡੑ͕େࣄ w ςετͷՄಡੑ ฐࣾͷϏϑΥʔΞϑλʔ w ςετ݁ՌͷՄಡੑ

  4. ࠓ೔ͷ໨ඪ ͎͘ʙɺςετͷՄಡੑ͋͛ͯ͐ʙ

  5. ຊ೔ͷ಺༰ IUUQTHJUIVCDPNEBJLJ fl VUUFS@UFTU@XJUI@SFBEBCJMJUZ

  6. ຊ೔ͷ಺༰

  7. ຊ೔ͷྲྀΕ

  8. Կ΋ҙࣝͤͣॻ͍ͨ ςετ͕͋Δ

  9. None
  10. ͜ΕΛ ͭͷύοέʔδͳͲΛ ࢖ͬͯՄಡੑΛ্͛ͯΈΑ͏ʂ

  11. ͱɺͦͷલʹʂ

  12. ͦ΋ͦ΋ ςετʹՄಡੑ͸ඞཁ͔ʁ

  13. :&4ʂ

  14. ςετʹՄಡੑ͸ඞཁ͔ʁ w ςετ͸ίʔυͷઆ໌ॻ w ΋ͪΖΜਖ਼͘͠ಈ͔͘Ͳ͏͔Λ୲อ͢Δͱ͍͏ଆ໘΋͋Δ ͦͷҰํͰɺ w ࢲ͸͜͏͍͏෩ʹಈ͘ίʔυΛॻ͍ͨΑ w ͜͏͍͏ೖྗ஋Λ૝ఆ͍ͯ͠ΔΑ

    w ͜͏͍͏࣌͸ΤϥʔΛग़͢Α ͱ͍͏આ໌ॻɺҙࢥද໌ʹ΋ͳ͍ͬͯΔ
  15. ςετͷՄಡੑ͕௿͍ ʹ Կ͕ݴ͍͍ͨͷ͔෼͔Βͳ͍ ςετʹՄಡੑ͸ඞཁ͔ʁ

  16. ͔ͩΒɺςετ͸ ಡΈ΍͘͢ॻ͜͏ͳʁ ݁࿦

  17. ςετͷՄಡੑ w HSPVQ w HJWFO@XIFO@UIFO w fl VUUFS@UFTU@VJ

  18. HSPVQ

  19. ςετͷՄಡੑ w ͝ଘ஌ͷํ΋ଟ͍͸ͣ w fl VUUFS@UFTUʹಉࠝ͞Ε͍ͯΔϝιου w ͦͷ໊ͷ௨Γɺෳ਺ͷςετΛάϧʔϓԽग़དྷΔ HSPVQ

  20. None
  21. JODSFNFOUCVUUPO EFDSFNFOUCVUUPO

  22. ςετͷՄಡੑ

  23. ςετͷՄಡੑ group('[Increment Button]', () { group('label shows "0"', () {

    testWidgets('label shows "1"', (WidgetTester tester) async { }); }); group('label shows "1"', () { testWidgets('label shows "2"', (WidgetTester tester) async { }); }); });
  24. ςετͷՄಡੑ group('[Decrement Button]', () { group('label shows "1"', () {

    testWidgets('label shows "0"', (WidgetTester tester) async { }); }); group('label shows "2"', () { testWidgets('label shows "1"', (WidgetTester tester) async { }); }); });
  25. HSPVQ ݸॏͳͬͱΔΜ΍͚Ͳʁ

  26. ςετͷՄಡੑ group('[Increment Button]', () { group('label shows "0"', () {

    testWidgets('label shows "1"', (WidgetTester tester) async { }); }); group('label shows "1"', () { testWidgets('label shows "2"', (WidgetTester tester) async { }); }); });
  27. ςετͷՄಡੑ group('[Increment Button]', () { ← describe group('label shows "0"',

    () { ← context testWidgets('label shows "1"' ← it, (WidgetTester tester) async { }); }); group('label shows "1"', () { testWidgets('label shows "2"', (WidgetTester tester) async { }); }); });
  28. ςετͷՄಡੑ w 34QFDͰ࠾༻͞Ε͍ͯΔه๏ w EFTDSJCF ɹςετର৅ w DPOUFYU ɹςετΛߦ͏લఏ৚݅ w

    JU ɹͲ͏ͳ͍ͬͯΔ΂͖͔ JUTIPVMECFͷҙຯͷJU EFTDSJCF DPOUFYU  JUFYBNQMF 
  29. ςετͷՄಡੑ group('[Increment Button]', () { ← describe group('label shows "0"',

    () { ← context testWidgets('label shows "1"' ← it, (WidgetTester tester) async { }); }); group('label shows "1"', () { testWidgets('label shows "2"', (WidgetTester tester) async { }); }); });
  30. ςετͷՄಡੑ group('[Increment Button]', () { ← describe group('label shows "0"',

    () { ← context testWidgets('label shows "1"' ← it, (WidgetTester tester) async { }); }); group('label shows "1"', () { testWidgets('label shows "2"', (WidgetTester tester) async { }); }); });
  31. ςετͷՄಡੑ group('[Increment Button]', () { ← describe group('label shows "0"',

    () { ← context testWidgets('label shows "1"' ← it, (WidgetTester tester) async { }); }); group('label shows "1"', () { testWidgets('label shows "2"', (WidgetTester tester) async { }); }); });
  32. ςετͷՄಡੑ group('[Increment Button]', () { group('label shows "0"', () {

    testWidgets('label shows "1"', (WidgetTester tester) async { }); }); group('label shows "1"', () { testWidgets('label shows "2"', (WidgetTester tester) async { }); }); });
  33. HJWFO@XIFO@UIFO

  34. ςετͷՄಡੑ ςετͬͯ݁ہͷͱ͜Ζ͜Μͳߏ੒Ͱ੒Γཱ͍ͬͯΔ HJWFO@XIFO@UIFO

  35. ςετͷՄಡੑ ͋Δ৚݅Ͱɺ͋Δಈ࡞Λͨ͠Β͜͏ͳͬͯ΄͍͠ HJWFO@XIFO@UIFO

  36. ςετͷՄಡੑ ͋Δ৚݅Ͱɺ͋Δಈ࡞Λͨ͠Β͜͏ͳͬͯ΄͍͠ HJWFO@XIFO@UIFO HJWFO

  37. ςετͷՄಡੑ ͋Δ৚݅Ͱɺ͋Δಈ࡞Λͨ͠Β͜͏ͳͬͯ΄͍͠ HJWFO@XIFO@UIFO XIFO HJWFO

  38. ςετͷՄಡੑ ͋Δ৚݅Ͱɺ͋Δಈ࡞Λͨ͠Β͜͏ͳͬͯ΄͍͠ HJWFO@XIFO@UIFO UIFO XIFO HJWFO

  39. ྫ͑͹

  40. ςετͷՄಡੑ ͕දࣔ͞Ε͍ͯΔ࣌ʹ ϓϥεϘλϯΛԡͨ͠Β ͕දࣔ͞Ε͍ͯͯཉ͍͠ HJWFO@XIFO@UIFO HJWFO

  41. ςετͷՄಡੑ ͕දࣔ͞Ε͍ͯΔ࣌ʹ ϓϥεϘλϯΛԡͨ͠Β ͕දࣔ͞Ε͍ͯͯཉ͍͠ HJWFO@XIFO@UIFO HJWFO XIFO

  42. ςετͷՄಡੑ ͕දࣔ͞Ε͍ͯΔ࣌ʹ ϓϥεϘλϯΛԡͨ͠Β ͕දࣔ͞Ε͍ͯͯཉ͍͠ HJWFO@XIFO@UIFO HJWFO XIFO UIFO

  43. ςετͷՄಡੑ HJWFO@XIFO@UIFO testWidgets('label shows "1"', harness((given, when, then) async {

    { await given.pumpMyApp(); given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } }), );
  44. ςετͷՄಡੑ HJWFO@XIFO@UIFO testWidgets('label shows "1"', harness((given, when, then) async {

    { await given.pumpMyApp(); given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } }), ); ͕දࣔ͞Ε͍ͯΔ࣌ʹ
  45. ςετͷՄಡੑ HJWFO@XIFO@UIFO testWidgets('label shows "1"', harness((given, when, then) async {

    { await given.pumpMyApp(); given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } }), ); ϓϥεϘλϯ͕ԡ͞ΕͨΒ ͕දࣔ͞Ε͍ͯΔ࣌ʹ
  46. ςετͷՄಡੑ HJWFO@XIFO@UIFO testWidgets('label shows "1"', harness((given, when, then) async {

    { await given.pumpMyApp(); given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } }), ); ϓϥεϘλϯ͕ԡ͞ΕͨΒ ͕දࣔ͞Ε͍ͯΔ࣌ʹ ͕දࣔ͞Ε͍ͯͯཉ͍͠
  47. ςετͷՄಡੑ ղઆ HJWFO@XIFO@UIFO

  48. ςετͷՄಡੑ HJWFO@XIFO@UIFO testWidgets('label shows "1"', harness((given, when, then) async {

    { await given.pumpMyApp(); given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } }), );
  49. ςετͷՄಡੑ HJWFO@XIFO@UIFO

  50. ςετͷՄಡੑ HJWFO@XIFO@UIFO extension MyAppGiven on WidgetTestGiven<_MyAppTestHarness> { Future<void> pumpMyApp() async

    { await tester.pumpWidget(const MyApp()); } Future<void> increment() async { await tester.tap(find.byKey(incrementKey)); } Future<void> pump() async { await tester.pump(); } void canFindZero() { expect(find.text('0'), findsOneWidget); } void cannotFindZero() { expect(find.text('0'), findsNothing); }}
  51. ςετͷՄಡੑ HJWFO@XIFO@UIFO extension MyAppWhen on WidgetTestWhen<_MyAppTestHarness> { Future<void> userTapsIncrementButton() async

    { await tester.tap(find.byKey(incrementKey)); await tester.pump(); } Future<void> userTapsDecrementButton() async { await tester.tap(find.byKey(decrementKey)); await tester.pump(); } }
  52. ςετͷՄಡੑ HJWFO@XIFO@UIFO extension MyAppThen on WidgetTestThen<_MyAppTestHarness> { void canFindZero() {

    expect(find.text('0'), findsOneWidget); } void cannotFindZero() { expect(find.text('0'), findsNothing); } void canFindOne() { expect(find.text('1'), findsOneWidget); } void cannotFindOne() { expect(find.text('1'), findsNothing); } void canFindTwo() { expect(find.text('2'), findsOneWidget); } void cannotFindTwo() { expect(find.text('2'), findsNothing); } }
  53. ςετͷՄಡੑ HJWFO@XIFO@UIFO testWidgets('label shows "1"', harness((given, when, then) async {

    { await given.pumpMyApp(); given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } }), );
  54. ςετͷՄಡੑ HJWFO@XIFO@UIFO testWidgets('label shows "2"', harness((given, when, then) async {

    { await given.pumpMyApp(); await given.increment(); await given.pump(); given.canFindOne(); given.cannotFindTwo(); } { await when.userTapsIncrementButton(); } { then.cannotFindOne(); then.canFindTwo(); } }));
  55. testWidgets('label shows "1"', harness((given, when, then) async { { await

    given.pumpMyApp(); await given.increment(); await given.increment(); await given.pump(); given.canFindTwo(); given.cannotFindOne(); } { await when.userTapsDecrementButton(); } { then.cannotFindTwo(); then.canFindOne(); } })); ςετͷՄಡੑ HJWFO@XIFO@UIFO
  56. ςετͷՄಡੑ HJWFO@XIFO@UIFO ͪΐͬͱେม͡ΌͶʁ

  57. ςετͷՄಡੑ HJWFO@XIFO@UIFOͷ؆қ൛ testWidgets('label shows "1"', (WidgetTester tester) async { //

    given { await tester.pumpWidget(const MyApp()); expect(find.text('0'), findsOneWidget); expect(find.text('1'), findsNothing); } // when { await tester.tap(find.byKey(incrementKey)); await tester.pump(); } // then { expect(find.text('0'), findsNothing); expect(find.text('1'), findsOneWidget); } });
  58. fl VUUFS@UFTU@VJ

  59. ςετͷՄಡੑ GMVUUFS@UFTU@VJ void main() { setUpUI((tester) async { await tester.pumpWidget(const

    MyApp()); }); testUI('label shows "1"', harness((given, when, then) async { { given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } })); }
  60. ςετͷՄಡੑ GMVUUFS@UFTU@VJ w testUI, setupUI, tearDownUIͳͲɺ6*ςετ༻ͷϝιουΛఏڙ

  61. ςετͷՄಡੑ GMVUUFS@UFTU@VJ testWidgets('label shows "1"', harness((given, when, then) async {

    { await given.pumpMyApp(); given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } }), );
  62. ςετͷՄಡੑ HJWFO@XIFO@UIFO testWidgets('label shows "1"', harness((given, when, then) async {

    { await given.pumpMyApp(); given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } }), );
  63. ςετͷՄಡੑ GMVUUFS@UFTU@VJ void main() { setUpUI((tester) async { await tester.pumpWidget(const

    MyApp()); }); testUI('label shows "1"', harness((given, when, then) async { { given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } })); }
  64. ςετͷՄಡੑ GMVUUFS@UFTU@VJ void main() { setUpUI((tester) async { await tester.pumpWidget(const

    MyApp()); }); testUI('label shows "1"', harness((given, when, then) async { { given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } })); }
  65. ςετͷՄಡੑ GMVUUFS@UFTU@VJ void main() { setUpUI((tester) async { await tester.pumpWidget(const

    MyApp()); }); testUI('label shows "1"', harness((given, when, then) async { { given.canFindZero(); given.cannotFindOne(); } { await when.userTapsIncrementButton(); } { then.cannotFindZero(); then.canFindOne(); } })); }
  66. group('label shows "2"', () { setUpUI((tester) async { await tester.tap(find.byKey(incrementKey));

    await tester.tap(find.byKey(incrementKey)); await tester.pump(); }); testUI('label shows "1"', harness((given, when, then) async { { given.canFindTwo(); given.cannotFindOne(); } { await when.userTapsDecrementButton(); } { then.cannotFindTwo(); then.canFindOne(); } })); }); ςετͷՄಡੑ GMVUUFS@UFTU@VJ
  67. ฐࣾͰͷϏϑΥʔΞϑλʔ

  68. ฐࣾͰͷϏϑΥʔΞϑλʔ  "3FRVFTU #3FRVFTU $3FRVFTU "QJ$MJFOU "3FTQPOTF #3FTQPOTF $3FTQPOTF $PNNBOEύλʔϯ

    "QJ 3FRV FTU
  69.  "3FRVFTU #3FRVFTU $3FRVFTU "QJ$MJFOU "3FTQPOTF #3FTQPOTF $3FTQPOTF $PNNBOEύλʔϯ "QJ

    3FRV FTU ฐࣾͰͷϏϑΥʔΞϑλʔ
  70.  "3FRVFTU #3FRVFTU $3FRVFTU "QJ$MJFOU "3FTQPOTF #3FTQPOTF $3FTQPOTF $PNNBOEύλʔϯ "QJ

    3FRV FTU ฐࣾͰͷϏϑΥʔΞϑλʔ
  71.  "3FRVFTU #3FRVFTU $3FRVFTU "QJ$MJFOU "3FTQPOTF #3FTQPOTF $3FTQPOTF $PNNBOEύλʔϯ "QJ

    3FRV FTU ฐࣾͰͷϏϑΥʔΞϑλʔ
  72.  ฐࣾͰͷϏϑΥʔΞϑλʔ

  73.  ฐࣾͰͷϏϑΥʔΞϑλʔ

  74. ฐࣾͰͷϏϑΥʔΞϑλʔ

  75. ฐࣾͰͷϏϑΥʔΞϑλʔ

  76. ฐࣾͰͷϏϑΥʔΞϑλʔ ςετΛͭ௥Ճ͢ΔͨΊʹ༷ʑͳϑΝΠϧΛ௥Ճมߋ͢Δඞཁ͕͋Δ w UFTUSFTPVSDFT഑Լ w KTPOͷ௥Ճ w 'BLF"QJ$MJFOU w ϞοΫύεͷઃఆ

    w ๨ΕΔͱImplementationError w xxxTest σϝϦοτ
  77. ฐࣾͰͷϏϑΥʔΞϑλʔ ͪΐͬͱ͚ͩҧ͏ϨεϙϯεΛ࡞Δͷʹ৽ͨͳKTPO͕ඞཁ ɾ༑ୡͷ༗ແ ɾϑΥϩʔঢ়ଶ ɾϒϩοΫঢ়ଶ σϝϦοτ

  78. ฐࣾͰͷϏϑΥʔΞϑλʔ σϝϦοτ มߋʹରͯ͠ίϯύΠϧηʔϑͰͳ͍ ɾ6TFS͔ΒϓϩύςΟΛҰͭݮΒͨ͠ ɹɹKTPO΋ม͑ͳ͖Ό͍͚ͳ͍͜ͱͳΜͯ୭΋ؾ෇͔ͳ͍ΑͶস

  79. Ξϑλʔ

  80. ฐࣾͰͷϏϑΥʔΞϑλʔ Ξϑλʔ typedef FakeApiResponder = dynamic Function(ApiRequest<dynamic>);

  81. ฐࣾͰͷϏϑΥʔΞϑλʔ Ξϑλʔ FakeApiClientImpl appending({ required FakeApiResponder responder, }) { return

    FakeApiClientImpl._( responders: [..._responders, responder], ); }
  82. )PXUPVTFʁ

  83. ฐࣾͰͷϏϑΥʔΞϑλʔ Ξϑλʔ void main() { final baseApiClient = FakeApiClientImpl.create(); setUpAll(TestWidgetsFlutterBinding.ensureInitialized);

    // Test cases... }
  84. ฐࣾͰͷϏϑΥʔΞϑλʔ Ξϑλʔ final apiClient = baseApiClient.appending( responder: (request) { if

    (request is UsersRequest) { return _Fixtures.createUser( id: 'some_user_id', ); } }, );
  85. ฐࣾͰͷϏϑΥʔΞϑλʔ Ξϑλʔ class _Fixtures { static User createUser() { return

    User(id: 'hoge', name: 'ashdik'); } }
  86. ฐࣾͰͷϏϑΥʔΞϑλʔ ςετΛͭ௥Ճ͢ΔͨΊʹ༷ʑͳϑΝΠϧΛ௥Ճมߋ͢Δඞཁ͕͋Δ ɹˠͦΕͧΕͷςετͷΈʂ ͪΐͬͱ͚ͩҧ͏ϨεϙϯεΛ࡞Δͷʹ৽ͨͳKTPO͕ඞཁ ɹˠ@'JYUVSFͷҾ਺ʹม͍͑ͨ஋ΛऔΔ͚ͩ มߋʹରͯ͠ίϯύΠϧηʔϑͰͳ͍ ɹˠ6TFSΫϥεΛ௚઀ΠϯελϯεԽ͍ͯ͠Δ σϝϦοτ

  87. ςετ݁ՌͷՄಡੑ

  88. EBSU@EPU@SFQPSUFS

  89. ςετ݁ՌͷՄಡੑ w σϑΥϧτͰ͸ ओʹࣦഊ࣌ ಡΈͮΒ͍ʜ GMVUUFSUFTU

  90. ςετ݁ՌͷՄಡੑ w ಡΈ΍͍͢🎉

  91. ςετ݁ՌͷՄಡੑ w EPU@SFQPSUFSΠϯεύΠΞ w ςετ݁ՌΛݟ΍ͯ͘͘͢͠ΕΔ w ʮʯ ɹ੒ޭ w ʮ9ʯ

    ɹࣦഊ w ʮʯ ɹεΩοϓ EBSU@EPU@SFQPSUFS
  92. ςετ݁ՌͷՄಡੑ ͩΜͩΜಡΈ΍ͯ͘͢͠ΈΑ͏ GMVUUFSUFTUNBDIJOF

  93. w ҎԼ2εςοϓ ςετ݁ՌͷՄಡੑ w pubspec.yamlʹdart_dot_reporterΛ௥Ճ EBSU@EPU@SFQPSUFSɹʙԼ४උʙ GMVUUFSQVCHMPCBMBDUJWBUFEBSU@EPU@SFQPSUFS

  94. ςετ݁ՌͷՄಡੑ ͩΜͩΜಡΈ΍ͯ͘͢͠ΈΑ͏ GMVUUFSUFTUNBDIJOFNBDIJOFMPH GMVUUFSQVCHMPCBMSVOEBSU@EPU@SFQPSUFSNBDIJOFMPH

  95. ςετ݁ՌͷՄಡੑ ͩΜͩΜಡΈ΍ͯ͘͢͠ΈΑ͏

  96. ͦͷଞ w SJWFSQPE w fl VUUFS@HIFSLJO w NPDLJOHKBZ w NPDLJUP

    w CEE@XJEHFU@UFTU w PHVSFUT ঺հ͖͠Εͳ͔ͬͨύοέʔδͨͪ
  97.  ਖ਼ࣾһ Λݟਾ͑ͨۀ຿ҕୗͷํ ืूதʂ

  98.  ͝ਗ਼ௌɺ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ