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
TypeScriptとテストをはじめた
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
syukai
April 25, 2019
Programming
1.1k
0
Share
TypeScriptとテストをはじめた
v-kansai #5の登壇資料です。
JavaScriptで書いたVue.jsをTypeScriptに書き直してユニットテストを追加した話
syukai
April 25, 2019
More Decks by syukai
See All by syukai
SpringBoot+MyBatisで例外が出たときどこを見るか
syukai
0
370
ブランチ運用とデプロイフローを見直してリリースを楽にする
syukai
4
1.3k
ノート付き-ブランチ運用とデプロイフローを見直してリリースを楽にする
syukai
0
100
一歩ずつ進めるVue.js
syukai
2
420
kanjava20170326
syukai
0
640
Other Decks in Programming
See All in Programming
レガシーPHP転生 〜父がドメインエキスパートだったのでDDD+Claude Codeでチート開発します〜
panda_program
0
910
t *testing.T は どこからやってくるの?
otakakot
1
530
年間50登壇、単著出版、雑誌寄稿、Podcast出演、YouTube、CM、カンファレンス主催……全部やってみたので面白さ等を比較してみよう / I’ve tried them all, so let’s compare how interesting they are.
nrslib
4
780
ルールルルルルRubyの中身の予備知識 ── RubyKaigiの前に予習しなイカ?
ydah
1
180
ハンズオンで学ぶクラウドネイティブ
tatsukiminami
0
130
Google Nest CamとApple Vision frameworkと猫🐈🐈⬛ / onishi50
yutailang0119
0
110
Exploring RuboCop with MCP
koic
0
680
Kubernetes上でAgentを動かすための最新動向と押さえるべき概念まとめ
sotamaki0421
3
490
Liberating Ruby's Parser from Lexer Hacks
ydah
2
740
의존성 주입과 모듈화
fornewid
0
130
Offline should be the norm: building local-first apps with CRDTs & Kotlin Multiplatform
renaudmathieu
0
210
ふりがな Deep Dive try! Swift Tokyo 2026
watura
0
210
Featured
See All Featured
Being A Developer After 40
akosma
91
590k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
110
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.8k
Tell your own story through comics
letsgokoyo
1
890
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.3k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.4k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.4k
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
0
270
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
99
WENDY [Excerpt]
tessaabrams
10
37k
Transcript
5ZQF4DSJQUͱςετ Λ͡Ίͨ WLBOTBJ !TZVLBJ
ࣗݾհ ϢΧΠ !TZVLBJ ීஈͬͯΔ͜ͱ w +BWB w 4QSJOH #PPU
w 7VFKT w /&5ͪΐͬ͜ͱ
લճ ͷ͓͞Β͍ w 5ZQF4DSJQUͷಋೖ͕ݱࡏਐߦܗ w Ϣχοτςετͷಋೖݱࡏਐߦܗ w ࢲ͡Όͳ͍ਓ͕ؤுͬͯΔ͚ͲπϥΠ
5ZQF4DSJQU
5ZQF4DSJQUಋೖ w ͢Ͱʹ+BWB4DSJQUͰग़དྷ্͕ͬͯΔͷΛมߋ w ͬͺΓܕ͕ͳ͍ͱ͠ΜͲ͍ w ίʔυॻ͍ͯͯʮ͜ΕͷܕͳΜ͚ͩͬʁʯͱ͔໘ w Τϥʔݟ͔ͯΒʮ͋ʔͦ͏͍จࣈྻͩͬͨΘʯ w
໊߲ͱ͔74$PEF༷ʹڭ͑ͯ΄͍͠ w εϖϧϛε͕࣮ߦ࣌ʹൃ֮ͱ͔ɾɾɾ
QBDLBHFKTPO w WVFDMJͰ࡞ͬͨΩϨΠͳQBDLBHFKTPOʹඞཁͳͷΛҠ ২ w WVFNBUFSJBM༻ʹ!UZQFTWVFNBUFSJBMΛՃ w OQNJOTUBMM͢ΔͱQBDLBHFKTPO͔Βফ͑Δɾɾɾ
ͱΓ͋͑ͣίϯύΠϧ௨͢ w KTΛUTʹม͑Δ w จ๏ͷҧ͍Λมߋ w FYQPSUɺQSPQ NFUIPE DPNQVUFEɺSPVUFSUT w
BOZ͍ͬͯͬͺ͍ॻ͍ͨ w ͱΓ͋͑ͣίϯύΠϧ௨ͬͯͳΜͱͳ͘ಈ͚͍ͬͨΜ҆ ৺Ͱ͖Δ
<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'; } })
ܕΛݫ֨ʹ͍ͯ͘͠ w ͨΓલ͚ͩͲBOZͰશવخ͘͠ͳ͍ w TIJNTNZ.PEFMEUTΛ࡞ͬͯJOUFSGBDFͱͯ͠ܕΛఆٛ w BOZΛͪΌΜͱͨ͠ܕʹॻ͖͍͑ͯ͘ w JOQVU͕Λͯ͘͠ΕΔΑ͏ʹ͢Δ WNPEFM⇛WNPEFMOVNCFS
<<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” />
5ZQF4DSJQUରԠͷ্͛ w &4MJOUΛ54MJOUʹมߋ w 54MJOUWVFDMJQMVHJOUZQFTDSJQUͷͷΛ༻
Ϣχοτςετ
͠ΌΓ͍ͨ͜ͱ ΫοΫϒοΫʹ ΄΅ॻ͍ͯ͋ͬͨ Vue.jsΫοΫϒοΫɿVue ίϯϙʔωϯτͷ୯ମςετ https://jp.vuejs.org/v2/cookbook/unit-testing-vue-components.html
ͳͥςετΛ͢ΔͷͰ͔͢ ίϯϙʔωϯτͷ୯ମςετʹͨ͘͞Μͷར͕͋Γ·͢: • ίϯϙʔωϯτ͕Ͳ͏ಈ࡞͖͔͢ͷυΩϡϝϯτΛఏڙ͠ ·͢ • աͳखಈςετͷ࣌ؒΛઅ͠·͢ • ৽͍͠ػೳʹ͓͚ΔόάΛݮΒ͠·͢ •
ઃܭΛվྑ͠·͢ • ϦϑΝΫλϦϯάΛ༰қʹ͠·͢ ࣗಈςετେنͳ։ൃνʔϜ͕ෳࡶͳίʔυϕʔεΛอͭ ͜ͱΛՄೳʹ͠·͢ɻ
࣮ྫ ୯ମςετͷ͖͢͜ͱ: • ࣮ߦ͕ૣ͍͜ͱ • ཧղ͍͢͜͠ͱ • Ұͭͷ࡞ۀ ͚ͩΛςετ͢Δ͜ͱ ʢதུʣ
্هςετʹ͍͔ͭ͘ͷ͕͋Γ·͢: • 1ͭͷςετ͕ҟͳΔ͜ͱʹ͍ͭͯΞαʔγϣϯΛߦ͍ͬͯ·͢ • ίϯϙʔωϯτ͕ଘࡏͰ͖ΔҟͳΔঢ়ଶඳը͖͢ͷΛ͑Δͷ͕͍͠ ҎԼͷྫͰɺςετΛ࣍ͷΑ͏ʹվળ͍͖ͯ͠·͢: • it ϒϩοΫ͝ͱʹ1ͭͷΞαʔγϣϯͷΈ࡞͢Δ • ͘໌֬ͳςετͷઆ໌Λ࣋ͭ • ςετʹඞཁͳ࠷ݶͷσʔλ͚ͩΛఏڙ͢Δ • ॏෳͨ͠ϩδοΫʢwrapper ͷ࡞ͱ username มͷઃఆʣΛϑΝΫτϦؔ ʹϦϑΝΫλϦϯά͢Δ
ͦΕͦΕͱͯ͠ ͱΓ͋͑ͣ͠·͢
+FTU w ެࣜΛݟͳ͕Β+FTUରԠΛਐΊΔ
ࢀߟ w ʮ͡Ίͯͷࣗಈςετʯ w ςετͷߟ͑ํΓ͚ํ
Ϣχοτςετ
ํ w ςετΛཉுΒͳ͍ w 6*ςετఘΊΔ w ֎෦࿈ܞఘΊΔ w QSJWBUFͷςετέʔε͍Βͳ͍ w
͍͖ͳΓશ෦ٻΊͳ͍ʂϢχοτϨϕϧͷ҆શ֬อʂ
ྫʣ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 ͦΕҎ֎Λςετ͢Δඞཁͳ͠
ςετέʔε w JU̍ͭͰ̍ςετέʔεʹ͢Δʂ w ͳΜͷςετ͔ͩΘ͔Βͳ͘ͳΔ w JUͷ్தͰೖσʔλΛೖΕସ͑ͳ͍ w Ξαʔγϣϯෳ͋ͬͯΑ͍ ͭͷೖσʔλͰෳͷ߲ɾঢ়ଶΛ֬ೝ͢Δ
ྫʣ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); });
ྫʣ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); });
"1*ݺͼग़͠ͷςετ w "1*ݺͼग़͠ʹ"YJPTΛ༻ w ϢχοτςετͰ"1*ݺͼग़ͨ͘͠͠ͳ͍ʂ w "YJPTͬͨ"1*ݺͼग़͠ॲཧΛಠཱͤ͞Δ w ্هॲཧΛϞοΫʹஔ͖͑Δ
ྫʣ"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 }; })
ը໘දࣔͷςετ w Βͳ͍ʂʂʂʂ w 7VFKT͔ͩΒσʔλ͕େৎͳΒදࣔେৎͩΖʂ w େৎͳΜͩΑʂʂʂʂ w ͱ͍͑USBOTJUJPO͕͏·͘ಈ͍ͯΔ͔ɺσʔλͷ࠶ܭࢉ ͕ͪΌΜͱԠͯ͠Δ͔ؾʹͳΔͱ͜Ζ
⇛Ͳ͏͠Α͏
ςετॻ͍ͯಘͨݟ
ίϯϙʔωϯτখ͘͢͞Δ w Ͱ͔͍ίϯϙʔωϯτπϥΠɻখ͘͞͠Α͏ w ͨΒϞοΫʹཔΖ͏ͱ͢Δ͜ͱʹͳΓɺͦͯ͠ϋϚΔ w ςετέʔεͷΈ߹Θ͕ͤෳࡶʹͳΔ w ςετίʔυ͕͘ͳΓಡΉؾ͕ࣦͤΔ w
ςετέʔεΓͯΔ͔Θ͔Μͳ͍
ΫϥεΛੵۃతʹ࡞Δ w ΫϥεʹΓग़ͯ͠QSJWBUFʹ͢ΕࢀরՕॴ͕ݮͬͯς ετύλʔϯ͕άοͱߜΕΔ w ॻ͍ͯͯؾ͍͚ͮͨͲςετύλʔϯߟ͑Δͷ͕໘ͬͯ ͜ͱӨڹՕॴଟ͍͔Βόάग़͍ͬͯ͢͜ͱͩΑͶ
5ZQF4DSJQU͡Όͳ͍ͱπϥΠ w ผͷҊ݅Ͱ+BWB4DSJQUͷ··ςετͯ͠Έͨ w GVODUJPOͷϞοΫࠩ͠ସ͕͍͑͠ ϦϙδτϦͷςετ͕πϥΠ w Ұ5ZQF4DSJQUΔͱ͏ܕແ͍ͷ໘͍͘͞
·ͩ·ͩΘ͔Βͳ͍ͷͰ ͬͱςετॻ͜͏
͝ਗ਼ௌ ͋Γ͕ͱ͏͍͟͝·ͨ͠