Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

ຊ೔ͷ಺༰

Slide 7

Slide 7 text

ຊ೔ͷྲྀΕ

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

ͱɺͦͷલʹʂ

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

:&4ʂ

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

ςετͷՄಡੑ͕௿͍ ʹ Կ͕ݴ͍͍ͨͷ͔෼͔Βͳ͍ ςετʹՄಡੑ͸ඞཁ͔ʁ

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

HSPVQ

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

JODSFNFOUCVUUPO EFDSFNFOUCVUUPO

Slide 22

Slide 22 text

ςετͷՄಡੑ

Slide 23

Slide 23 text

ςετͷՄಡੑ 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 { }); }); });

Slide 24

Slide 24 text

ςετͷՄಡੑ 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 { }); }); });

Slide 25

Slide 25 text

HSPVQ ݸॏͳͬͱΔΜ΍͚Ͳʁ

Slide 26

Slide 26 text

ςετͷՄಡੑ 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 { }); }); });

Slide 27

Slide 27 text

ςετͷՄಡੑ 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 { }); }); });

Slide 28

Slide 28 text

ςετͷՄಡੑ w 34QFDͰ࠾༻͞Ε͍ͯΔه๏ w EFTDSJCF ɹςετର৅ w DPOUFYU ɹςετΛߦ͏લఏ৚݅ w JU ɹͲ͏ͳ͍ͬͯΔ΂͖͔ JUTIPVMECFͷҙຯͷJU EFTDSJCF DPOUFYU JUFYBNQMF

Slide 29

Slide 29 text

ςετͷՄಡੑ 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 { }); }); });

Slide 30

Slide 30 text

ςετͷՄಡੑ 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 { }); }); });

Slide 31

Slide 31 text

ςετͷՄಡੑ 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 { }); }); });

Slide 32

Slide 32 text

ςετͷՄಡੑ 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 { }); }); });

Slide 33

Slide 33 text

HJWFO@XIFO@UIFO

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

ྫ͑͹

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

ςετͷՄಡੑ 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(); } }), );

Slide 44

Slide 44 text

ςετͷՄಡੑ 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(); } }), ); ͕දࣔ͞Ε͍ͯΔ࣌ʹ

Slide 45

Slide 45 text

ςετͷՄಡੑ 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(); } }), ); ϓϥεϘλϯ͕ԡ͞ΕͨΒ ͕දࣔ͞Ε͍ͯΔ࣌ʹ

Slide 46

Slide 46 text

ςετͷՄಡੑ 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(); } }), ); ϓϥεϘλϯ͕ԡ͞ΕͨΒ ͕දࣔ͞Ε͍ͯΔ࣌ʹ ͕දࣔ͞Ε͍ͯͯཉ͍͠

Slide 47

Slide 47 text

ςετͷՄಡੑ ղઆ HJWFO@XIFO@UIFO

Slide 48

Slide 48 text

ςετͷՄಡੑ 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(); } }), );

Slide 49

Slide 49 text

ςετͷՄಡੑ HJWFO@XIFO@UIFO

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

ςετͷՄಡੑ 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); } }

Slide 53

Slide 53 text

ςετͷՄಡੑ 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(); } }), );

Slide 54

Slide 54 text

ςετͷՄಡੑ 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(); } }));

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

ςετͷՄಡੑ HJWFO@XIFO@UIFO ͪΐͬͱେม͡ΌͶʁ

Slide 57

Slide 57 text

ςετͷՄಡੑ 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); } });

Slide 58

Slide 58 text

fl VUUFS@UFTU@VJ

Slide 59

Slide 59 text

ςετͷՄಡੑ 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(); } })); }

Slide 60

Slide 60 text

ςετͷՄಡੑ GMVUUFS@UFTU@VJ w testUI, setupUI, tearDownUIͳͲɺ6*ςετ༻ͷϝιουΛఏڙ

Slide 61

Slide 61 text

ςετͷՄಡੑ 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(); } }), );

Slide 62

Slide 62 text

ςετͷՄಡੑ 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(); } }), );

Slide 63

Slide 63 text

ςετͷՄಡੑ 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(); } })); }

Slide 64

Slide 64 text

ςετͷՄಡੑ 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(); } })); }

Slide 65

Slide 65 text

ςετͷՄಡੑ 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(); } })); }

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

Ξϑλʔ

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

ฐࣾͰͷϏϑΥʔΞϑλʔ Ξϑλʔ FakeApiClientImpl appending({ required FakeApiResponder responder, }) { return FakeApiClientImpl._( responders: [..._responders, responder], ); }

Slide 82

Slide 82 text

)PXUPVTFʁ

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

ฐࣾͰͷϏϑΥʔΞϑλʔ Ξϑλʔ final apiClient = baseApiClient.appending( responder: (request) { if (request is UsersRequest) { return _Fixtures.createUser( id: 'some_user_id', ); } }, );

Slide 85

Slide 85 text

ฐࣾͰͷϏϑΥʔΞϑλʔ Ξϑλʔ class _Fixtures { static User createUser() { return User(id: 'hoge', name: 'ashdik'); } }

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

ςετ݁ՌͷՄಡੑ

Slide 88

Slide 88 text

EBSU@EPU@SFQPSUFS

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

ͦͷଞ w SJWFSQPE w fl VUUFS@HIFSLJO w NPDLJOHKBZ w NPDLJUP w CEE@XJEHFU@UFTU w PHVSFUT ঺հ͖͠Εͳ͔ͬͨύοέʔδͨͪ

Slide 97

Slide 97 text

ਖ਼ࣾһ Λݟਾ͑ͨۀ຿ҕୗͷํ ืूதʂ

Slide 98

Slide 98 text

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