TypeScriptとテストをはじめた

0f27061b9503c11f119ef338ed5be479?s=47 syukai
April 25, 2019

 TypeScriptとテストをはじめた

v-kansai #5の登壇資料です。
JavaScriptで書いたVue.jsをTypeScriptに書き直してユニットテストを追加した話

0f27061b9503c11f119ef338ed5be479?s=128

syukai

April 25, 2019
Tweet

Transcript

  1. 5ZQF4DSJQUͱςετ Λ͸͡Ίͨ WLBOTBJ !TZVLBJ

  2. ࣗݾ঺հ ϢΧΠ !TZVLBJ ීஈ΍ͬͯΔ͜ͱ w +BWB w 4QSJOH #PPU 

    w 7VFKT w /&5΋ͪΐͬ͜ͱ
  3. લճ  ͷ͓͞Β͍ w 5ZQF4DSJQUͷಋೖ͕ݱࡏਐߦܗ w Ϣχοτςετͷಋೖ΋ݱࡏਐߦܗ w ࢲ͡Όͳ͍ਓ͕ؤுͬͯΔ͚ͲπϥΠ

  4. 5ZQF4DSJQU

  5. 5ZQF4DSJQUಋೖ w ͢Ͱʹ+BWB4DSJQUͰग़དྷ্͕ͬͯΔ΋ͷΛมߋ w ΍ͬͺΓܕ͕ͳ͍ͱ͠ΜͲ͍ w ίʔυॻ͍ͯͯʮ͜ΕͷܕͳΜ͚ͩͬʁʯͱ͔໘౗ w Τϥʔݟ͔ͯΒʮ͋ʔͦ͏͍΍จࣈྻͩͬͨΘʯ w

    ߲໨໊ͱ͔74$PEF༷ʹڭ͑ͯ΄͍͠ w εϖϧϛε͕࣮ߦ࣌ʹൃ֮ͱ͔ɾɾɾ
  6. QBDLBHFKTPO w WVFDMJͰ࡞ͬͨΩϨΠͳQBDLBHFKTPOʹඞཁͳ΋ͷΛҠ ২ w WVFNBUFSJBM༻ʹ!UZQFTWVFNBUFSJBMΛ௥Ճ w OQNJOTUBMM͢ΔͱQBDLBHFKTPO͔Βফ͑Δɾɾɾ

  7. ͱΓ͋͑ͣίϯύΠϧ௨͢ w KTΛUTʹม͑Δ w จ๏ͷҧ͍Λมߋ w FYQPSUɺQSPQ NFUIPE DPNQVUFEɺSPVUFSUT w

    BOZ͍ͬͯͬͺ͍ॻ͍ͨ w ͱΓ͋͑ͣίϯύΠϧ௨ͬͯͳΜͱͳ͘ಈ͚͹͍ͬͨΜ҆ ৺Ͱ͖Δ
  8. <script> JavaScript export default { props: ['model', 'mode'], data() {

    return {}; }, computed: { isAmode() { return this.mode === 'A'; } } } <script lang=“ts"> TypeScript import Vue from 'vue' @Component({}) export default class Card extends Vue { @prop() model!: any; @prop() mode!: string; /** computed */ get isAmode() { return this.mode === 'A'; } })
  9. ܕΛݫ֨ʹ͍ͯ͘͠ w ౰ͨΓલ͚ͩͲBOZͰ͸શવخ͘͠ͳ͍ w TIJNTNZ.PEFMEUTΛ࡞ͬͯJOUFSGBDFͱͯ͠ܕΛఆٛ w BOZΛͪΌΜͱͨ͠ܕʹॻ͖׵͍͑ͯ͘ w JOQVU͕਺஋Λ౉ͯ͘͠ΕΔΑ͏ʹ͢Δ
 WNPEFM⇛WNPEFMOVNCFS

  10. <<Employee.d.ts>> // RestAPIͰड͚औΔσʔλͷܕ export = Employee; declare interface Employee {

    id: string; name: string; } <<shims-myModel.d.ts>> import _Employee from '@/model/Employee'; export = myModel; declare module myModel { export interface Employee extends _Employee {} } <<template>> <input v-model.number=“age” />
  11. 5ZQF4DSJQUରԠͷ࢓্͛ w &4MJOUΛ54MJOUʹมߋ w 54MJOU͸WVFDMJQMVHJOUZQFTDSJQUͷ΋ͷΛ࢖༻

  12. Ϣχοτςετ

  13. ͠Ό΂Γ͍ͨ͜ͱ͸ ΫοΫϒοΫʹ ΄΅ॻ͍ͯ͋ͬͨ Vue.jsΫοΫϒοΫɿVue ίϯϙʔωϯτͷ୯ମςετ https://jp.vuejs.org/v2/cookbook/unit-testing-vue-components.html

  14. ͳͥςετΛ͢ΔͷͰ͔͢ ίϯϙʔωϯτͷ୯ମςετʹ͸ͨ͘͞Μͷར఺͕͋Γ·͢: • ίϯϙʔωϯτ͕Ͳ͏ಈ࡞͢΂͖͔ͷυΩϡϝϯτΛఏڙ͠ ·͢ • ա౓ͳखಈςετͷ࣌ؒΛઅ໿͠·͢ • ৽͍͠ػೳʹ͓͚ΔόάΛݮΒ͠·͢ •

    ઃܭΛվྑ͠·͢ • ϦϑΝΫλϦϯάΛ༰қʹ͠·͢ ࣗಈςετ͸େن໛ͳ։ൃνʔϜ͕ෳࡶͳίʔυϕʔεΛอͭ ͜ͱΛՄೳʹ͠·͢ɻ
  15. ࣮ྫ ୯ମςετͷ͢΂͖͜ͱ͸: • ࣮ߦ͕ૣ͍͜ͱ • ཧղ͠΍͍͢͜ͱ • Ұͭͷ࡞ۀ ͚ͩΛςετ͢Δ͜ͱ ʢதུʣ

    ্هςετʹ͸͍͔ͭ͘ͷ໰୊͕͋Γ·͢: • 1ͭͷςετ͕ҟͳΔ͜ͱʹ͍ͭͯΞαʔγϣϯΛߦ͍ͬͯ·͢ • ίϯϙʔωϯτ͕ଘࡏͰ͖ΔҟͳΔঢ়ଶ΍ඳը͢΂͖΋ͷΛ఻͑Δͷ͕೉͍͠ ҎԼͷྫͰ͸ɺςετΛ࣍ͷΑ͏ʹվળ͍͖ͯ͠·͢: • it ϒϩοΫ͝ͱʹ1ͭͷΞαʔγϣϯͷΈ࡞੒͢Δ • ୹͘໌֬ͳςετͷઆ໌Λ࣋ͭ • ςετʹඞཁͳ࠷௿ݶͷσʔλ͚ͩΛఏڙ͢Δ • ॏෳͨ͠ϩδοΫʢwrapper ͷ࡞੒ͱ username ม਺ͷઃఆʣΛϑΝΫτϦؔ ਺ʹϦϑΝΫλϦϯά͢Δ
  16. ͦΕ͸ͦΕͱͯ͠ ͱΓ͋͑ͣ࿩͠·͢

  17. +FTU w ެࣜΛݟͳ͕Β+FTUରԠΛਐΊΔ

  18. ࢀߟ w ʮ͸͡Ίͯͷࣗಈςετʯ w ςετͷߟ͑ํ΍੾Γ෼͚ํ

  19. Ϣχοτςετ

  20. ํ਑ w ςετΛཉுΒͳ͍ w 6*ςετ͸ఘΊΔ w ֎෦࿈ܞ΋ఘΊΔ w QSJWBUFͷςετέʔε͸͍Βͳ͍ w

    ͍͖ͳΓશ෦͸ٻΊͳ͍ʂϢχοτϨϕϧͷ҆શ֬อʂ
  21. ྫʣQSJWBUF prevMonth(): void { this.addMonth(-1); } nextMonth(): void { this.addMonth(1);

    } private addMonth(months: number): void { let nextYear: number = Number(this.yyyy); let nextMonth: number = Number(this.mm) + months; if(nextMonth === 13) { nextYear += 1; nextMonth = 1; } else if (nextMonth === 0) { nextYear -= 1; nextMonth = 12; } this.yyyy = nextYear; this.mm = nextMonth; } w ʢ࣮૷͕ΞϨͳͷ͸͓͖ͯ͞ʜʣ w BEE.POUIͷҾ਺͸͔͔͋͠ Γ͑ͳ͍ w ͦΕҎ֎Λςετ͢Δඞཁͳ͠
  22. ςετέʔε w JU̍ͭͰ̍ςετέʔεʹ͢Δʂ w ͳΜͷςετ͔ͩΘ͔Βͳ͘ͳΔ w JUͷ్தͰ౤ೖσʔλΛೖΕସ͑ͳ͍ w Ξαʔγϣϯ͸ෳ਺͋ͬͯΑ͍
 ͭͷ౤ೖσʔλͰෳ਺ͷ߲໨ɾঢ়ଶΛ֬ೝ͢Δ

  23. ྫʣJU̍ͭͰ̍ςετέʔε <<before>> it('ϙΠϯτ͕ϚΠφεͳΒ0ʹ͢Δ', () => { wrapper.vm.form.points = 1; wrapper.vm.onValidPoint();

    expect(wrapper.vm.form.points).toBe(1); wrapper.vm.form.points = -1; wrapper.vm.onValidPoint(); expect(wrapper.vm.form.points).toBe(0); });
  24. ྫʣJU̍ͭͰ̍ςετέʔε <<after>> it(‘onValidPoint ௨ৗ', () => { wrapper.vm.form.points = 1;

    wrapper.vm.onValidPoint(); expect(wrapper.vm.form.points).toBe(1); }); it(‘onValidPoint ϚΠφε', () => { wrapper.vm.form.points = -1; wrapper.vm.onValidPoint(); expect(wrapper.vm.form.points).toBe(0); });
  25. "1*ݺͼग़͠ͷςετ w "1*ݺͼग़͠ʹ͸"YJPTΛ࢖༻ w ϢχοτςετͰ͸"1*ݺͼग़ͨ͘͠͠ͳ͍ʂ w "YJPT࢖ͬͨ"1*ݺͼग़͠ॲཧΛಠཱͤ͞Δ w ্هॲཧΛϞοΫʹஔ͖׵͑Δ

  26. ྫʣ"QJΛݺͼग़͠Λಠཱ <<EmpoyeesApi.ts>> import axiosBase from '@/module/AxiosBase' let axios = axiosBase.axios;

    export default { getEmployees(): Promise<any> { return axios.get('employees'); } } <<hoge.spec.ts>>ɹaxiosࠩ͠ସ͑͸େมͳͷͰApi͝ͱࠩ͠ସ͑ const getEmployeesMock = jest.fn(); jest.mock('@/module/api/EmployeesApi', () => { return { getEmployees: getEmployeesMock }; })
  27. ը໘දࣔͷςετ w ΍Βͳ͍ʂʂʂʂ w 7VFKT͔ͩΒσʔλ͕େৎ෉ͳΒදࣔ΋େৎ෉ͩΖʂ w େৎ෉ͳΜͩΑʂʂʂʂ w ͱ͸͍͑USBOTJUJPO͕͏·͘ಈ͍ͯΔ͔ɺσʔλͷ࠶ܭࢉ ͕ͪΌΜͱ൓Ԡͯ͠Δ͔͸ؾʹͳΔͱ͜Ζ


    ⇛Ͳ͏͠Α͏
  28. ςετॻ͍ͯಘͨ஌ݟ

  29. ίϯϙʔωϯτ͸খ͘͢͞Δ w Ͱ͔͍ίϯϙʔωϯτ͸πϥΠɻখ͘͞͠Α͏ w ΍ͨΒϞοΫʹཔΖ͏ͱ͢Δ͜ͱʹͳΓɺͦͯ͠ϋϚΔ w ςετέʔεͷ૊Έ߹Θ͕ͤෳࡶʹͳΔ w ςετίʔυ͕௕͘ͳΓಡΉؾ͕ࣦͤΔ w

    ςετέʔε଍ΓͯΔ͔Θ͔Μͳ͍
  30. ΫϥεΛੵۃతʹ࡞Δ w Ϋϥεʹ੾Γग़ͯ͠QSJWBUFʹ͢Ε͹ࢀরՕॴ͕ݮͬͯς ετύλʔϯ͕άοͱߜΕΔ w ॻ͍ͯͯؾ͍͚ͮͨͲςετύλʔϯߟ͑Δͷ͕໘౗ͬͯ ͜ͱ͸ӨڹՕॴଟ͍͔Βόάग़΍͍ͬͯ͢͜ͱͩΑͶ

  31. 5ZQF4DSJQU͡Όͳ͍ͱπϥΠ w ผͷҊ݅Ͱ+BWB4DSJQUͷ··ςετͯ͠Έͨ w GVODUJPOͷϞοΫࠩ͠ସ͕͑೉͍͠
 ϦϙδτϦͷςετ͕πϥΠ w Ұ౓5ZQF4DSJQU΍Δͱ΋͏ܕແ͍ͷ໘౗͍͘͞

  32. ·ͩ·ͩΘ͔Βͳ͍ͷͰ ΋ͬͱςετॻ͜͏

  33. ͝ਗ਼ௌ ͋Γ͕ͱ͏͍͟͝·ͨ͠