Slide 1

Slide 1 text

TypeScriptͱJestͰ͸͡ΊΔ AWS੡αʔόʔϨε REST API ͷϢχοτςετ/E2Eςετ #serverlessfukuoka

Slide 2

Slide 2 text

ςετίʔυΛॻ͍ͯ΄͍͠

Slide 3

Slide 3 text

αʔόʔϨε։ൃք۾ͷ՝୊ ΞʔΩςΫνϟύλʔϯ ϚωʔδυαʔϏε ֤αʔϏεͷ࢖͍ํ ΞϓϦέʔγϣϯύλʔϯ σϓϩΠύλʔϯ ςετ ॆ࣮͖ͯͨ͠ ՝୊͕࢒Δʢࣄྫෆ଍ʣ

Slide 4

Slide 4 text

αʔόʔϨε։ൃք۾ͷ՝୊ ΞʔΩςΫνϟύλʔϯ ϚωʔδυαʔϏε ֤αʔϏεͷ࢖͍ํ ΞϓϦέʔγϣϯύλʔϯ σϓϩΠύλʔϯ ςετ ॆ࣮͖ͯͨ͠ ՝୊͕࢒Δʢࣄྫෆ଍ʣ lॳظ։ൃzʹඞཁ lܧଓ։ൃzʹඞཁ

Slide 5

Slide 5 text

େࠓ೔ࢀߟʹ͍͍ͤͯͨͩͨ͞৘ใ ࿨ా୎ਓ, 2017/6/2 AWS Dev Day Tokyo 2017 IUUQTTQFBLFSEFDLDPNUXBEBUFTUBCMFMBNCEBXPSLJOHF⒎FDUJWFMZXJUIMFHBDZMBNCEB Testable Lambda Working Effectivery with Legacy Lambda Clean Architecture ୡਓʹֶͿιϑτ΢ΣΞͷ ߏ଄ͱઃܭ Robert C. Martin ςετۦಈ։ൃ Kent Beck, ࿨ా୎ਓ

Slide 6

Slide 6 text

ࣗݾ঺հ ࿨ా༞հ 
 $9ࣄۀຊ෦
 αʔόʔϨεΤϯδχΞ XBEEZ@V ٕज़ॻయ7

Slide 7

Slide 7 text

ࠓ೔ͷ͓୊ʹ࢖Θ͍͍ͤͯͨͩͨΞϓϦέʔγϣϯ 4#(JGU༷ΪϑταʔϏεόοΫΤϯυͷҰ෦

Slide 8

Slide 8 text

αʔόʔαΠυͷςετʹ΋࢖͑Δ+FTU ΦʔϧΠϯϫϯ ςετϥϯφʔɺΞαʔγϣϯɺςετμϒϧɺΧόϨοδ Ϩϙʔτ UTKFTUͰ5ZQF4DSJQUͷςετίʔυΛ௚઀࣮ߦՄೳ "84$%,Ͱ࠾༻͞Ε͍ͯΔ

Slide 9

Slide 9 text

ൃදͷ໨ඪ ςετίʔυΛॻ͘ϋʔυϧΛԼ͛Δ͜ͱ ͦͷͨΊʹɿ αʔόʔϨεͰlίεύͷྑ͍zςετઓज़Λ੔ཧ͢Δ
 Ϣχοτςετɾ&&ςετ͕ର৅ ͍ͭͰʹɿ αʔόʔϨεΞϓϦέʔγϣϯ։ൃʹ໾ཱͭ
 +FTUͷ5JQTΛ঺հ͢Δ

Slide 10

Slide 10 text

ࠓ೔ग़ͯ͘ΔαʔόʔϨεΞϓϦͷલఏ w ओʹ"84αʔϏεΛ࢖ͬͯ w αʔόʔϨεͰ w ϏδωεϩδοΫΛ༗͢Δ w 8FC"1*Λ࡞Δ ͱ͍͏લఏͰ͢

Slide 11

Slide 11 text

ΞδΣϯμ ޮ཰ͷྑ͍ςετઓज़ ! ϢχοτςετͱΞϓϦέʔγϣϯઃܭ E2EςετͱΞʔΩςΫνϟύλʔϯ ·ͱΊ

Slide 12

Slide 12 text

ςετޮ཰ͷҰൠతͳΞϓϩʔνɿଟஈࣜΤϥʔϓϧʔϑ σόοάͷૣ͞ͱྔ͸τϨʔυΦϑͳͷͰஈ֊తͳςετ͕๬·͍͠ͱ͍͏ߟ͑ํ ׳ΕΔʁJS ૉૣ͘ڀ໌ʂσόοάೖ໳ https://speakerdeck.com/orgachem/guan-reru-js- su-zao-kujiu-ming-debatuguru-men?slide=32 Kuniwak

Slide 13

Slide 13 text

ҰൠతͳΞϓϩʔνɿଟஈࣜΤϥʔϓϧʔϑ σόοάͷૣ͞ͱྔ͸τϨʔυΦϑͳͷͰஈ֊తͳςετ͕๬·͍͠ͱ͍͏ߟ͑ํ ׳ΕΔʁJS ૉૣ͘ڀ໌ʂσόοάೖ໳ https://speakerdeck.com/orgachem/guan-reru-js- su-zao-kujiu-ming-debatuguru-men?slide=32 Kuniwak αʔόʔϨεͰ΋͓ͳ͡

Slide 14

Slide 14 text

ςετޮ཰ͷҰൠతͳΞϓϩʔνɿଟஈࣜΤϥʔϓϧʔϑ σόοάͷૣ͞ͱྔ͸τϨʔυΦϑͳͷͰஈ֊తͳςετ͕๬·͍͠ͱ͍͏ߟ͑ํ ׳ΕΔʁJS ૉૣ͘ڀ໌ʂσόοάೖ໳ https://speakerdeck.com/orgachem/guan-reru-js- su-zao-kujiu-ming-debatuguru-men?slide=32 Kuniwak 5ZQF4DSJQUΛ ࢖͏ཧ༝͕͜Ε

Slide 15

Slide 15 text

ҰൠతͳΞϓϩʔνɿଟஈࣜΤϥʔϓϧʔϑ σόοάͷૣ͞ͱྔ͸τϨʔυΦϑͳͷͰஈ֊తͳςετ͕๬·͍͠ͱ͍͏ߟ͑ํ ׳ΕΔʁJS ૉૣ͘ڀ໌ʂσόοάೖ໳ https://speakerdeck.com/orgachem/guan-reru-js- su-zao-kujiu-ming-debatuguru-men?slide=32 Kuniwak ࣍͸͜ͷதͷ ޮ཰Λߟ͑Δ

Slide 16

Slide 16 text

ΞδΣϯμ ޮ཰ͷྑ͍ςετઓज़ ϢχοτςετͱΞϓϦέʔγϣϯઃܭ! E2EςετͱΞʔΩςΫνϟύλʔϯ ·ͱΊ

Slide 17

Slide 17 text

Ϣχοτςετɿ-BNCEB'VODUJPO͸ԿͰ͔͢ʁ ೖग़ྗͷ͋Δؔ਺ʁ:&4͕ͩͦΕʹཹ·Βͳ͍ ֎෦͔ΒೖྗΛड͚औΓɺϏδωεϩδοΫΛࢪͯ͠ɺ
 ผͷαʔϏεΛݺͿ ΞϓϦέʔγϣϯͷ໾ׂΛ୲͏͜ͱ΋૿͖͑ͯͨ ΞϓϦέʔγϣϯͩͱ͢ΔͱɺઃܭΛߟ͑Δҙຯ͕͋Δ

Slide 18

Slide 18 text

4#(JGU༷ΪϑταʔϏεόοΫΤϯυͷҰ෦ ྫ͑͹νέοτ৘ใͷফࠐ -BNCEB'VODUJPO

Slide 19

Slide 19 text

4#(JGU༷ΪϑταʔϏεόοΫΤϯυͷҰ෦ ྫ͑͹νέοτ৘ใͷফࠐ -BNCEB'VODUJPO

Slide 20

Slide 20 text

4#(JGU༷ΪϑταʔϏεόοΫΤϯυͷҰ෦ ྫ͑͹νέοτ৘ใͷফࠐ -BNCEB'VODUJPO IBOEMFS &YDIBOHF,JOFTJT)BOEMFS

Slide 21

Slide 21 text

4#(JGU༷ΪϑταʔϏεόοΫΤϯυͷҰ෦ ྫ͑͹νέοτ৘ใͷফࠐ -BNCEB'VODUJPO IBOEMFS &YDIBOHF,JOFTJT)BOEMFS $MFBS5JDLFU6TF$BTF 7BMJEBUPST EPNBJO

Slide 22

Slide 22 text

4#(JGU༷ΪϑταʔϏεόοΫΤϯυͷҰ෦ ྫ͑͹νέοτ৘ใͷফࠐ -BNCEB'VODUJPO IBOEMFS &YDIBOHF,JOFTJT)BOEMFS $MFBS5JDLFU6TF$BTF $MFBS5JDLFU"QJ$BMMFS 7BMJEBUPST EPNBJO JOGSB

Slide 23

Slide 23 text

4#(JGU༷ΪϑταʔϏεόοΫΤϯυͷҰ෦ ྫ͑͹νέοτ৘ใͷফࠐ -BNCEB'VODUJPO IBOEMFS &YDIBOHF,JOFTJT)BOEMFS $MFBS5JDLFU6TF$BTF $MFBS5JDLFU"QJ$BMMFS DPNQPOFOU 7BMJEBUPST EPNBJO JOGSB

Slide 24

Slide 24 text

4#(JGU༷ΪϑταʔϏεόοΫΤϯυͷҰ෦ ྫ͑͹νέοτ৘ใͷফࠐ -BNCEB'VODUJPO IBOEMFS &YDIBOHF,JOFTJT)BOEMFS $MFBS5JDLFU6TF$BTF $MFBS5JDLFU"QJ$BMMFS DPNQPOFOU 7BMJEBUPST EPNBJO JOGSB ϨΠϠผɺػೳผʹ ίʔυΛ෼ྨ

Slide 25

Slide 25 text

ΞϓϦέʔγϣϯઃܭΛखʹೖΕͨ αʔόʔϨεͷੈքʹ͍Ζ͍ΖͳσβΠϯύλʔϯ͕ྲྀ ༻Ͱ͖Δ )VNCMF0CKFDUύλʔϯ ϢχοτςετΛ࣮ߦ͢Δਓ͕ɺςετ͠ʹ͍͘ৼΔ෣͍ͱ ςετ͠΍͍͢ৼΔ෣͍Λ෼ྨ͢ΔͨΊʹੜ·Εͨ ֎քͱ΍ΓͱΓ͢ΔϨΠϠͷίʔυΛՄೳͳݶΓബ͘͢Δ

Slide 26

Slide 26 text

)VNCMF0CKFDUύλʔϯͷద༻ IBOEMFS &YDIBOHF,JOFTJT)BOEMFS $MFBS5JDLFU6TF$BTF $MFBS5JDLFU"QJ$BMMFS DPNQPOFOU 7BMJEBUPST EPNBJO JOGSB ͜͜Λް͘ʂ

Slide 27

Slide 27 text

)VNCMF0CKFDUύλʔϯͷద༻ IBOEMFS &YDIBOHF,JOFTJT)BOEMFS $MFBS5JDLFU6TF$BTF $MFBS5JDLFU"QJ$BMMFS DPNQPOFOU 7BMJEBUPST EPNBJO JOGSB ͜͜͸ബ͘ʂ ɾ+40/ͷม׵ ɾॲཧݺͼग़͠ ͘Β͍ʹͳΔΑ͏ؤுΔ

Slide 28

Slide 28 text

ϐϡΞϩδοΫΛॆ࣮ͤ͞Ε͹ςετޮ཰61 ςετ͠ʹ͍͘ՕॴΛബͨ͘͜͠ͱͰɺϐϡΞϩδοΫ ͕ॆ࣮ͨ͠ ͜͜ʹରͯ͠Ϣχοτςετ͸Πϝʔδ͠΍͍͢ )VNCMF0CKFDUʹͨ͠ͱ͜Ζ͸͍ͬͨΜϞοΫͰ0, -PDBM4UBDL΍4".-PDBMͷಋೖ͸ͪΐͬͱ4501 ͜ΕΒͰ֬ೝͰ͖Δର৅͸͍·͸)VNCMFͳʢബ͍ʣͷͰɻ

Slide 29

Slide 29 text

5JQTϞοΫԽʹ͸+FTUͷTQZ0O ͕໾ཱͭ describe('Clear ticket use case', () => { test('run clear ticket', async (): Promise => { const en = ExchangeNotification.of('123456'); const getTicketSpy = jest .spyOn(ticket, 'getTicket') .mockResolvedValue(searchTicket); const clearTicketSpy = jest .spyOn(ticket, 'clearTicket') .mockResolvedValue('Created:UT'); const result = await clearingTicketUseCase(en); expect(result).toEqual({ result: 'Created', }); expect(getTicketSpy).toHaveBeenCalledWith( en.ticketNo,en.shoriTime, ); expect(clearTicketSpy).toHaveBeenCalledWith(searchTicket); }); });

Slide 30

Slide 30 text

5JQTϞοΫԽʹ͸+FTUͷTQZ0O ͕໾ཱͭ describe('Clear ticket use case', () => { test('run clear ticket', async (): Promise => { const en = ExchangeNotification.of('123456'); const getTicketSpy = jest .spyOn(ticket, 'getTicket') .mockResolvedValue(searchTicket); const clearTicketSpy = jest .spyOn(ticket, 'clearTicket') .mockResolvedValue('Created:UT'); const result = await clearingTicketUseCase(en); expect(result).toEqual({ result: 'Created', }); expect(getTicketSpy).toHaveBeenCalledWith( en.ticketNo,en.shoriTime, ); expect(clearTicketSpy).toHaveBeenCalledWith(searchTicket); }); }); ͜ΕͰϩʔΧϧ࣮ߦՄೳ

Slide 31

Slide 31 text

5JQTϐϡΞϩδοΫͷ໢ཏʹ͸1BSBNFUFSJ[FE describe('NotNullValidator', () => { test.each` name | value | expected ${'address'} | ${'tokyo'} | ${{ isValid: true }} ${'first name'} | ${''} | ${{ isValid: true }} ${'first name'} | ${null} | ${{ isValid: false }} `( 'input $value, validation result expected: $expected.isValid', ({ name, value, expected }) => { const suc = new NotNullValidator(name, value); expect(suc.validate()).toEqual({ isValid: expected.isValid, }); }, ); });

Slide 32

Slide 32 text

5JQTϐϡΞϩδοΫͷ໢ཏʹ͸1BSBNFUFSJ[FE describe('NotNullValidator', () => { test.each` name | value | expected ${'address'} | ${'tokyo'} | ${{ isValid: true }} ${'first name'} | ${''} | ${{ isValid: true }} ${'first name'} | ${null} | ${{ isValid: false }} `( 'input $value, validation result expected: $expected.isValid', ({ name, value, expected }) => { const suc = new NotNullValidator(name, value); expect(suc.validate()).toEqual({ isValid: expected.isValid, }); }, ); }); ೖྗɾظ଴஋ϖΞΛςʔϒϧܗࣜͰఆٛ

Slide 33

Slide 33 text

Ϣχοτςετ·ͱΊ )VNCMF0CKFDUύλʔϯΛ࢖ͬͯϋϯυϥϨΠϠɺ ΠϯϑϥϨΠϠΛബ͘͢Δ ॆ࣮ͨ͠ϐϡΞϩδοΫʹରͯ͠ςετ͢Δ ͦͷࡍɺϞοΫԽͷͨΊͷTQZ0O έʔε໢ཏͷͨΊ ͷQBSBNFUFSJ[FEUFTUͰޮ཰ԽͰ͖Δ

Slide 34

Slide 34 text

ΞδΣϯμ ޮ཰ͷྑ͍ςετઓज़ ϢχοτςετͱΞϓϦέʔγϣϯઃܭ E2EςετͱΞʔΩςΫνϟύλʔϯ! ·ͱΊ

Slide 35

Slide 35 text

&&ςετͷఆٛʁ αʔϏεͷ࢓ࣄͿΓΛ֬ೝ͢ΔςετΛ&&ͱΈͳ͢ ࠓճͷ৔߹ͩͱσϓϩΠ͞Εͨ8FC"1*ͷ͜ͱ &&ྫɿ
 ϦΫΤετΛૹͬͨΒɺϨεϙϯε͕ฦͬͯ͘ΔͷͰɺͦΕ Λ֬ೝ͢Δ ϒϥ΢β͸࢖Θͳͯ͘΋0,

Slide 36

Slide 36 text

ਖ਼ৗέʔεΛ&&ςετͰҰຊ௨͢ σϓϩΠͨ͠ΞϓϦέʔγϣϯʹରͯ͠ਖ਼ৗܥຊͰྑ͍ αʔόʔϨεΞϓϦέʔγϣϯͰ͸ͱͯͭ΋ͳ͍Ձ஋͕͋Δ )VNCMF0CKFDU͕ਖ਼ৗܥͻͱͭͰಈ͍͍ͯΔ "84ߏ੒ͷ௨Γਖ਼ৗܥͻͱͭͰಈ͍͍ͯΔ ಛʹޙऀ͸-PDBM4UBDLͰ΋֬ೝͰ͖ͳ͍ ͍ΘΏΔʮಈ࡞֬ೝʯΛςετίʔυʹམͱ͢

Slide 37

Slide 37 text

8FC"1*࢓ࣄͷύλʔϯ ϦΫΤετϨεϙϯε ϦΫΤετσʔλอଘ ϦΫΤετ֎෦αʔϏε

Slide 38

Slide 38 text

8FC"1*࢓ࣄͷύλʔϯ ϦΫΤετϨεϙϯε ϦΫΤετσʔλอଘ ϦΫΤετ֎෦αʔϏε ϨεϙϯεϘσΟΛ֬ೝ

Slide 39

Slide 39 text

8FC"1*࢓ࣄͷύλʔϯ ϦΫΤετϨεϙϯε describe('exchange API', (): void => { test('clear ticket', async (): void => { const exchangeNotificationUrl = 'http://ticket-system.jp/ticket/clear'; const request = { shori_id: '01234567890', }; const response = await Axios.post( exchangeNotificationUrl, qs.stringify(request), ); expect(response.data).toEqual('{ "response": "ok" }'); }); });

Slide 40

Slide 40 text

8FC"1*࢓ࣄͷύλʔϯ ϦΫΤετϨεϙϯε describe('exchange API', (): void => { test('clear ticket', async (): void => { const exchangeNotificationUrl = 'http://ticket-system.jp/ticket/clear'; const request = { shori_id: '01234567890', }; const response = await Axios.post( exchangeNotificationUrl, qs.stringify(request), ); expect(response.data).toEqual('{ "response": "ok" }'); }); }); ϨεϙϯεϘσΟΛ֬ೝ

Slide 41

Slide 41 text

8FC"1*࢓ࣄͷύλʔϯ ϦΫΤετϨεϙϯε ϦΫΤετσʔλอଘ ϦΫΤετ֎෦αʔϏε อଘ͞ΕͨσʔλΛ֬ೝ

Slide 42

Slide 42 text

8FC"1*࢓ࣄͷύλʔϯ ϦΫΤετσʔλอଘ describe('exchange API', (): void => { test('clear ticket', async (): void => { // Axios request … // const param = { TableName: 'ticket-info', Key: { shoriId: '01234567890' }, }; const dynamoData = await dynamo.getItem(param).promsie(); expect(dynamoData).toEqual({ shoriId: request.shori_id, clear: true, }); }); });

Slide 43

Slide 43 text

8FC"1*࢓ࣄͷύλʔϯ ϦΫΤετσʔλอଘ describe('exchange API', (): void => { test('clear ticket', async (): void => { // Axios request … // const param = { TableName: 'ticket-info', Key: { shoriId: '01234567890' }, }; const dynamoData = await dynamo.getItem(param).promsie(); expect(dynamoData).toEqual({ shoriId: request.shori_id, clear: true, }); }); }); อଘ͞ΕͨσʔλΛ֬ೝ

Slide 44

Slide 44 text

8FC"1*࢓ࣄͷύλʔϯ ϦΫΤετϨεϙϯε ϦΫΤετσʔλอଘ ϦΫΤετ֎෦αʔϏε ໰୊͸͜Ε

Slide 45

Slide 45 text

ϦΫΤετ֎෦αʔϏείʔϧλΠϓ ࡞ͬͨ8FC"1*Ͱ׬݁͠ͳ͍͜ͱ͸βϥ 1BDUͰ$%$ςετͱ͍͏ख΋͋Δ͕ɺ·ͣ͸ࣗ෼͚ͨͪͩͰͰ͖Δ͜ ͱΛߟ͍͑ͨ ʮԶͨͪͷ੹೚ൣғ಺Ͱ͸ɺ΍Δ͜ͱ͸΍ͬͨʯͱ͍͏͜ͱ͕֬ೝͰ͖Ε ͹Α͍ ֎෦αʔϏεΛݺΜͩه࿥Λ࢒͓͖ͯ͠ɺͦͷه࿥͕ҙਤͲ͓ΓͰ͋Δ͜ ͱΛ֬ೝ ࣮૷ଆͷमਖ਼΋ඞཁ͕ͩɺ΍ΔՁ஋͸͋Δ Introduction - Pact https://docs.pact.io/

Slide 46

Slide 46 text

ྫɿ4ʹอଘͨ͠ॲཧه࿥Λࢀরͯ֬͠ೝ͢Δ describe('exchange API', (): void => { test('clear ticket', async (): Promise => { const exchangeNotificationUrl = 'http://ticket-system.jp/ticket/clear'; const request = { shori_id: '01234567890', }; const response = await Axios.post( exchangeNotificationUrl, qs.stringify(request), ); expect(response.data).toEqual('{ "response": "ok" }'); const param = { Bucket: 'ticket-info', Key: request.shori_id, }; const s3Obj = await s3.getObject(param).promsie(); const reocrd = JSON.parse(s3Obj.Body!.toString()); expect(reocrd).toEqual({ monitor: 'Created', }); }); });

Slide 47

Slide 47 text

ྫɿ4ʹอଘͨ͠ॲཧه࿥Λࢀরͯ֬͠ೝ͢Δ describe('exchange API', (): void => { test('clear ticket', async (): Promise => { const exchangeNotificationUrl = 'http://ticket-system.jp/ticket/clear'; const request = { shori_id: '01234567890', }; const response = await Axios.post( exchangeNotificationUrl, qs.stringify(request), ); expect(response.data).toEqual('{ "response": "ok" }'); const param = { Bucket: 'ticket-info', Key: request.shori_id, }; const s3Obj = await s3.getObject(param).promsie(); const reocrd = JSON.parse(s3Obj.Body!.toString()); expect(reocrd).toEqual({ monitor: 'Created', }); }); });

Slide 48

Slide 48 text

ྫɿ4ʹอଘͨ͠ॲཧه࿥Λࢀরͯ֬͠ೝ͢Δ describe('exchange API', (): void => { test('clear ticket', async (): Promise => { const exchangeNotificationUrl = 'http://ticket-system.jp/ticket/clear'; const request = { shori_id: '01234567890', }; const response = await Axios.post( exchangeNotificationUrl, qs.stringify(request), ); expect(response.data).toEqual('{ "response": "ok" }'); const param = { Bucket: 'ticket-info', Key: request.shori_id, }; const s3Obj = await s3.getObject(param).promsie(); const reocrd = JSON.parse(s3Obj.Body!.toString()); expect(reocrd).toEqual({ monitor: 'Created', }); }); }); ֎෦"1*͔Β$SFBUFE͕ ฦ͖ͬͯͨ͜ͱΛه࿥ɺ֬ೝ ※࣮ࡍʹ͸஗ԆͱϦτϥΠ͕ඞཁ

Slide 49

Slide 49 text

&&ςετ·ͱΊ ਖ਼ৗܥΛҰຊ௨͢͜ͱͰಘΒΕΔ҆৺ײ͸େ͖͍ αʔόʔϨεΞϓϦέʔγϣϯͷύλʔϯʹ߹Θͤͯɺ ·ͣॻ͘ ͦͷޙɺΤϥʔϨεϙϯεΛॆ࣮ͤͨ͞Γɺอଘ͢Δ σʔλͷόϦΤʔγϣϯΛ૿΍ͤ͹ྑ͍

Slide 50

Slide 50 text

ΞδΣϯμ ޮ཰ͷྑ͍ςετઓज़ ϢχοτςετͱΞϓϦέʔγϣϯઃܭ E2EςετͱΞʔΩςΫνϟύλʔϯ ·ͱΊ!

Slide 51

Slide 51 text

ϢχοτςετҎ߱ͷΤϥʔϓϧʔϑΟϯά )VNCMF0CKFDU ͷϢχοτςετ ϐϡΞϩδοΫͷϢχοτςετ ਖ਼ৗܥͷ&&ςετ ҟৗܥΛؚΉ&&ςετ 6 5 & & JSONม׵ϛε ϩδοΫߟྀ࿙Ε AWSߏ੒ϛε
 IAMϛε ࢓༷ͷෆ۩߹

Slide 52

Slide 52 text

ϢχοτςετͷΞϓϩʔν )VNCMF0CKFDU ͷϢχοτςετ ϐϡΞϩδοΫͷϢχοτςετ ਖ਼ৗܥͷ&&ςετ ҟৗܥΛؚΉ&&ςετ 6 5 & & JSONม׵ϛε ϩδοΫߟྀ࿙Ε AWSߏ੒ϛε
 IAMϛε ࢓༷ͷෆ۩߹ ςετ͠΍͍͢ϐϡΞϩδοΫͱͦΕҎ֎Λ෼ׂͨ͠

Slide 53

Slide 53 text

ϢχοτςετͷΞϓϩʔν )VNCMF0CKFDU ͷϢχοτςετ ϐϡΞϩδοΫͷϢχοτςετ ਖ਼ৗܥͷ&&ςετ ҟৗܥΛؚΉ&&ςετ 6 5 & & JSONม׵ϛε ϩδοΫߟྀ࿙Ε AWSߏ੒ϛε
 IAMϛε ࢓༷ͷෆ۩߹ +FTUͷػೳΛ׆༻ͯ͠ޮ཰ԽͰ͖Δ ɾspyOn() ʹΑΔϞοΫ ɾparameterized test

Slide 54

Slide 54 text

&&ςετ )VNCMF0CKFDU ͷϢχοτςετ ϐϡΞϩδοΫͷϢχοτςετ ਖ਼ৗܥͷ&&ςετ ҟৗܥΛؚΉ&&ςετ 6 5 & & JSONม׵ϛε ϩδοΫߟྀ࿙Ε AWSߏ੒ϛε
 IAMϛε ࢓༷ͷෆ۩߹ ·ͣ͸Ұຊ௨͢

Slide 55

Slide 55 text

&&ςετ )VNCMF0CKFDU ͷϢχοτςετ ϐϡΞϩδοΫͷϢχοτςετ ਖ਼ৗܥͷ&&ςετ ҟৗܥΛؚΉ&&ςετ 6 5 & & JSONม׵ϛε ϩδοΫߟྀ࿙Ε AWSߏ੒ϛε
 IAMϛε ࢓༷ͷෆ۩߹ ύλʔϯʹ߹Θ࣮ͤͯࢪ ɾϦΫΤετ-Ϩεϙϯε ɾϦΫΤετ-σʔλอଘ ɾϦΫΤετ-αʔϏείʔϧ

Slide 56

Slide 56 text

·ͱΊ )VNCMF0CKFDU ͷϢχοτςετ ϐϡΞϩδοΫͷϢχοτςετ ਖ਼ৗܥͷ&&ςετ ҟৗܥΛؚΉ&&ςετ 6 5 & & JSONม׵ϛε ϩδοΫߟྀ࿙Ε AWSߏ੒ϛε
 IAMϛε ࢓༷ͷෆ۩߹ ͜ͷ;ͨͭɺίεύ˕Ͱ͸͡Ί΍͍͢ʂ˞΋ͪΖΜ࠷ޙ͸શ෦΍Δ

Slide 57

Slide 57 text

͍͞͝ʹ ιϑτ΢ΣΞςετ͸ɺ਺ֶతূ໌Ͱ͸ͳ͘Պֶత൓ূ ʮগͳ͘ͱ΋͜ͷέʔεͰ͸ςετ͕ࣦഊ͠ͳ͍ʯ։ൃऀࣗ਎ͷͨ ΊͷূڌूΊ࡞ۀɻͲ͜·ͰԿΛ΍Δ͔ʁݶΒΕͨ࣌ؒͷͳ͔Ͱམ ͱ͠ॴΛܾΊͯޮ཰Λ্͛Δඞཁ͕͋Δ ۃ୺ͳ࿩ɺϝϯς༧ఆͷͳ͍ɺͨͩͻͱͭͷॲཧ͕͢Ͱʹόάͳ͘ ಈ͍͍ͯΔͷͳΒɺվΊͯςετΛॻ͘ඞཁ͸ͳ͍ Ͱ΋Ϗδωε͸੒௕͢Δ͠ɺ/PEFKTͷόʔδϣϯ΋্͕Δ͠ɺ 3%41SPYZ΋ొ৔͢ΔɻपΓ͕มԽ͢Δɻςετ͸ඞཁʹͳΔɻ ͦͷͱ͖ʹखΛ෇͚ΔͨΊͷࢀߟʹͳΕ͹޾͍Ͱ͢

Slide 58

Slide 58 text

େࠓ೔ࢀߟʹ͍͍ͤͯͨͩͨ͞৘ใ ࿨ా୎ਓ, 2017/6/2 AWS Dev Day Tokyo 2017 IUUQTTQFBLFSEFDLDPNUXBEBUFTUBCMFMBNCEBXPSLJOHF⒎FDUJWFMZXJUIMFHBDZMBNCEB Testable Lambda Working Effectivery with Legacy Lambda Clean Architecture ୡਓʹֶͿιϑτ΢ΣΞͷ ߏ଄ͱઃܭ Robert C. Martin ςετۦಈ։ൃ Kent Beck, ࿨ా୎ਓ