Slide 1

Slide 1 text

Testing Angular App @Quramy #ng-japan 2017.06.17

Slide 2

Slide 2 text

About me

Slide 3

Slide 3 text

About me w גࣜձࣾ8"$6-ॴଐͷϑϩϯτΤϯδχΞ w $PNNVOJUZ w OHKBQBO TUB⒎ w (SBQI2-5PLZP PSHBOJ[FS w ॻ੶ w ʮ&MFDUSPOͰ͸͡ΊΔΞϓϦ։ൃʯ w झຯ w 7JN5ZQF4DSJQUQMVHJOͷ։ൃϝϯς

Slide 4

Slide 4 text

Agenda w "OHVMBSͰԿΛ࡞͍ͬͯΔͷ͔ w Ͳ͏΍ͬͯςετͯ͠Δ͔ ੩తղੳฤ ୯ମςετฤ ࣗಈԽɾճؼςετฤ

Slide 5

Slide 5 text

ͲΜͳΞϓϦ࡞ͬͯΔͷ

Slide 6

Slide 6 text

AI Analyst w (PPHMF"OBMZUJDTͷσʔλΛղੳ
 8FCαΠτͷվળҊΛఏࣔ͢Δ##αʔϏε

Slide 7

Slide 7 text

Reopen after renovation w dͷ໿൒೥ؒͰϑϧεΫϥονϦχϡʔ ΞϧΛ࣮ࢪ w "OHVMBS+4WY"OHVMBSWͰ࡞Γ௚͠ w ࠷ऴతʹ'SPOUFOEͷίʔυ͸ MPDఔ౓

Slide 8

Slide 8 text

γεςϜߏ੒ w 4JOHMF1BHF"QQMJDBUJPO w 'SPOUFOE w 5ZQF4DSJQU"OHVMBS w #BDLFOE w 8FC"1*(PMBOH w %BUB"OBMZTJT#BUDI1ZUIPO 4DBMB

Slide 9

Slide 9 text

γεςϜಛੑ w σʔλղੳͱ͍͏αʔϏεͷ౎߹্ɺ࣮σʔλͰ݁Ռ֬ ೝ͕ߦ͑ΔΑ͏ʹͳΔ·Ͱ͕௕͍ w ؅ཧը໘͔ΒղੳδϣϒΛΩϡʔΠϯά w ղੳδϣϒͷ׬ྃΛ଴ͭ ਺෼d਺࣌ؒ w ղੳ݁ՌΛ"1*Ͱ(&5 w ݁Ռը໘Λඳը

Slide 10

Slide 10 text

γεςϜಛੑ w ղੳ݁Ռͷίϯτϩʔϧ͕೉͍͠ w */165(PPHMF"OBMZUJDT"1*Ͱऔಘͨ͠σʔλ w 065165֤छ౷ܭ΍ػցֶश͕ు͘਺஋ w ௨ৗ৮͍ͬͯΔ͚ͩͰ͸֬ೝͰ͖ͳ͍݁Ռը໘ύλʔϯ ͕͍ͬͺ͍

Slide 11

Slide 11 text

Τοδέʔε͸ ۃྗςετͰ௵͍ͨ͠

Slide 12

Slide 12 text

ͲͷΑ͏ʹςετ͍ͯ͠Δ͔ How test this app

Slide 13

Slide 13 text

1. ੩తղੳ Static Analysis

Slide 14

Slide 14 text

Compile = ࠷ॳͷςετ

Slide 15

Slide 15 text

Angular and TypeScript w "OHVMBSͱݴ͑͹5ZQF4DSJQU w .JDSPTPGU੡ͷ"MU+4 w ੩తͳܕ෇ WFSVQຖʹݡ͘ͳΔ ܕਪ࿦ w $PNQJMF͕௨Βͳ͍ίʔυͳΜͯ࿦֎ͩʂ

Slide 16

Slide 16 text

Compilation and Templates? w Ͱ΋)5.-ςϯϓϨʔτ͸୞ͷจࣈྻ w ԿΛॻ͍ͯ΋$PNQJMF௨ͬͪΌ͏͡ΌΜʜ import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: `

{{title}}

`, styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'app works!'; } It’s just string literal

Slide 17

Slide 17 text

AoT Compile w "P5 "IFBEPG5JNF $PNQJMF w ੩తʹ"OHVMBS$PNQPOFOUΛղੳͯ͠
 %0.ૢ࡞ίʔυΛੜ੒͢Δ͜ͱ w +J5 +VTUJO5JNF $PNQJMF w ࣮ߦ࣌ʹ$PNQPOFOU͔Β$PNQJMFͯ͠
 %0.ૢ࡞ؔ਺Λ࡞Γग़͢͜ͱ

Slide 18

Slide 18 text

AoT Compile w "P5$PNQJMF͸5ZQF4DSJQUιʔείʔυΛੜ੒͢Δ hoge.component.ts hoge.component.html hoge.component.css hoge.component.ngfactory.ts AoT Compilation

Slide 19

Slide 19 text

How to use AoT ? w !BOHVMBSDMJ w !BOHVMBSDPNQJMFSDMJ $ ng build --prod $ ngc -p tsconfig.json

Slide 20

Slide 20 text

(ࢀߟ) ݁Ռ͸͜Μͳײ͡

Slide 21

Slide 21 text

import * as i0 from './app.component.css.shim.ngstyle'; import * as i1 from '@angular/core'; import * as i2 from './app.component'; const styles_AppComponent:any[] = [i0.styles]; export const RenderType_AppComponent:i1.RendererType2 = i1.ɵcrt({encapsulation: 0,styles:styles_AppComponent, data:{}}); export function View_AppComponent_0(_l:any):i1.ɵViewDefinition { return i1.ɵvid(0,[(_l()(),i1.ɵeld(0,(null as any),(null as any),1,'h1',([] as any[]), (null as any),(null as any),(null as any),(null as any),(null as any))),(_l()(), i1.ɵted((null as any),['\n ','\n'])),(_l()(),i1.ɵted((null as any),['\n']))], (null as any),(_ck,_v) => { var _co:i2.AppComponent = _v.component; const currVal_0:any = _co.title; _ck(_v,1,0,currVal_0); }); } export function View_AppComponent_Host_0(_l:any):i1.ɵViewDefinition { return i1.ɵvid(0,[(_l()(),i1.ɵeld(0,(null as any),(null as any),1,'app-root',([] as any[]), (null as any),(null as any),(null as any),View_AppComponent_0,RenderType_AppComponent)), i1.ɵdid(49152,(null as any),0,i2.AppComponent,([] as any[]),(null as any),(null as any))], (null as any),(null as any)); } export const AppComponentNgFactory:i1.ComponentFactory = i1.ɵccf('app-root', i2.AppComponent,View_AppComponent_Host_0,{},{},([] as any[]));

Slide 22

Slide 22 text

Ε͖ͬͱͨ͠ TypeScript ιʔείʔυ
 (ਓ͕ؒಡΉ΋ͷ͡Όͳ͍͚Ͳ…)

Slide 23

Slide 23 text

AoT CompileͷԸܙ w ࣮ߦ࣌ύϑΥʔϚϯε ಛʹॳճඳը࣌ؒ ͷվળ w 5FNQMBUFͷ੩తίʔυνΣοΫ 㾎 "OHVMBS&YQSFTTJPOͷจ๏Τϥʔ 㾎 ଘࡏ͠ͳ͍ϓϩύςΟͷࢀর 㾎 ଘࡏ͠ͳ͍$PNQPOFOU%JSFDUJWF1JQFͷࢀর 㾎 FUD

Slide 24

Slide 24 text

Make more “strict” w --strictNPEF w 5ZQF4DSJQU͔Βར༻ՄೳͳΦϓγϣϯ w ԼهͷશΦϓγϣϯ͕༗ޮԽ͞ΕΔ --noImplicitAny --noImplicitThis --alwaysStrict --strictNullChecks

Slide 25

Slide 25 text

Strict null check example export interface Hoge { foo?: { bar: string; } } function main(hoge: Hoge) { // TS2532: Object is possibly 'undefined'. console.log(hoge.foo.bar); } hoge.foo͸OVMMVOEFpOFE͔΋ΑʁɹͱౖΒΕΔ

Slide 26

Slide 26 text

Null check example export interface Hoge { foo?: { bar: string; } } function main(hoge: Hoge) { if (hoge.foo) { console.log(hoge.foo.bar); } } ͪΌΜͱOVMMDIFDL͢ΔͱΤϥʔ͸ফ͑Δ

Slide 27

Slide 27 text

With Angular templates export interface Hoge { foo?: { bar: string; } } @Component({ selector: 'app-hoge', template: `
{{hoge.foo.bar}}
`, }) export class HogeComponent { @Input() hoge: Hoge; } ͜Ε͸Ͳ͏ͩΖ͏ʁ

Slide 28

Slide 28 text

Great! $ ng build --prod Hash: 797e0c8cdb3322d2d094 Time: 9762ms chunk {0} polyfills.c1dd16e57fa8d11134c9.bundle.js (polyfills) 158 kB {4} [initial] [rendered] chunk {1} main.a49bd4f47eb88687420a.bundle.js (main) 11.3 kB {3} [initial] [rendered] chunk {2} styles.d41d8cd98f00b204e980.bundle.css (styles) 69 bytes {4} [initial] [rendered] chunk {3} vendor.5b15b8462e82e6e78e7f.bundle.js (vendor) 1.14 MB [initial] [rendered] chunk {4} inline.f43fbe997f9c1fcc2775.bundle.js (inline) 0 bytes [entry] [rendered] ERROR in src/$$_gendir/app/hoge/ hoge.component.ngfactory.ts (19,27):
 Object is possibly 'undefined'. "P5͔͍͜͠ʂ

Slide 29

Slide 29 text

With Angular templates export interface Hoge { foo?: { bar: string; } } @Component({ selector: 'app-hoge', template: `
{{hoge.foo.bar}}
`, }) export class HogeComponent { @Input() hoge: Hoge; } ͪΌΜͱOVMMDIFDL͢ΔͱΤϥʔ͸ফ͑Δ

Slide 30

Slide 30 text

΋ͬͱૣ͘Τϥʔʹؾ෇͖͍ͨ w ϩʔΧϧ։ൃ࣌͸+J5$PNQJMFΛར༻ͯ͠։ൃ w $*Ͱ"P5Ϗϧυͨ͠ͱ͖ʹΤϥʔʹؾ෇͘ ൵͍͠ʜ

Slide 31

Slide 31 text

Language Service Plugin w 5ZQF4DSJQU͔Βͷ৽ػೳ w -BOHVBHF4FSWJDFΛࣗ༝ʹ֦ுՄೳʹ https://blogs.msdn.microsoft.com/typescript/2017/04/27/announcing-typescript-2-3/

Slide 32

Slide 32 text

What’s Language Service? w ΤσΟλʹ$PNQJMFSͷ৘ใΛಧ͚Δ໾ׂ https://github.com/Microsoft/TypeScript/wiki/Architectural-Overview#layer-overview

Slide 33

Slide 33 text

@angular/language-service w "OHVMBSνʔϜۘ੡ͷ-BOHVBHF4FSWJDF1MVHJO w ಺෦తʹ"P5$PNQJMFSΛར༻ w 5ZQF4DSJQUʹରԠͨ͠ΤσΟλɾ*%&Ͱಈ࡞ { "compilerOptions": { : "plugins": [ { "name": "@angular/language-service" } ] } }

Slide 34

Slide 34 text

With VSC

Slide 35

Slide 35 text

With Vim

Slide 36

Slide 36 text

Other tools for static analysis w IUUQTQBMBOUJSHJUIVCJPUTMJOU w IUUQTHJUIVCDPNNHFDIFWDPEFMZ[FS

Slide 37

Slide 37 text

2. ୯ମςετ
 Unit Testing

Slide 38

Slide 38 text

Angular ͱ୯ମςετ w 5FTUJOHؔ࿈ͷαϙʔτ΋खް͍
 ͕͢͞l0OF'SBNFXPSLz w "OHVMBSʹ͓͚Δඪ४5FTUTUBDL * ,BSNB ** +BTNJOF *** "OHVMBSUFTUJOHVUJMJUJFT

Slide 39

Slide 39 text

I. Karma w 5FTU3VOOFSGPS+BWB4DSJQU w 5FTUDPEFΛϒϥ΢βͰ࣮ߦ͢ΔͨΊͷUPPM w ϒϥ΢βͷىಈ w ςετίʔυͷૹΓࠐΈ TFSWFSCSPXTFS w ςετ݁Ռͷදࣔ CSPXTFSTFSWFS w FUD

Slide 40

Slide 40 text

II. Jasmine w 5FTUJOH'SBNFXPSLGPS+BWB4DSJQU w ࠷ॳ͔Β৭ʑೖͬͯΔ w %FTDSJCFTQFDT #%% w "TTFSUJPO w 4QZJOH w FUD w /PEFKTPS8FC#SPXTFSͷͲͪΒͰ΋ಈ࡞

Slide 41

Slide 41 text

Simple Jasmine example: describe('FizzBuzz', () => { it('should say Fizz when input can be divided 3', () => { expect(fizzBuzz(3)).toBe('Fizz'); }); it('should say Buzz when input can be divided 5', () => { expect(fizzBuzz(5)).toBe('Buzz'); }); });

Slide 42

Slide 42 text

III. Angular testing utilities w !BOHVMBSDPSFUFTUJOH w ςετ༻"OHVMBSNPEVMFͷηοτΞοϓ w ඇಉظ੍ޚؔ਺ w FUD w ଞʹ΋!BOHVMBSIUUQUFTUJOH΍!BOHVMBSSPVUFS UFTUJOHͳͲɺςετΛαϙʔτ͢Δػೳ܈͕ඪ४Ͱ෇͍ ͯ͘Δ

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

@angular/cli and test w ͔Βςετ͕ಈ࡞͢Δ؀ڥΛ࡞Δ͸݁ߏେมʜ w !BOHVMBSDMJʹ೚ͤΔͷ͕٢ w ,BSNBͷઃఆ XFCQBDLͷઃఆ UFTUDPEFͷTDB⒎PME w ͪͳΈʹFFUFTUJOH΋ηοτΞοϓͯ͘͠ΕΔ

Slide 45

Slide 45 text

Run test with @angular/cli $ ng new my-angualr-app $ cd my-angualr-app $ ng test —single-run Executed 3 of 3 SUCCESS (0.192 secs / 0.169 secs)

Slide 46

Slide 46 text

΍ͬͺΓؾʹͳΔͷ͸ Componentͷςετ

Slide 47

Slide 47 text

3 ways to Component Testing w "OHVMBS$PNQPOFOUͷςετύλʔϯ͸େ͖͘௨Γ * *TPMBUFE5FTUJOH ** 4IBMMPX5FTUJOH *** *OUFHSBUJPO5FTUJOH https://vsavkin.com/three-ways-to-test-angular-2-components-dcea8e90bd8d

Slide 48

Slide 48 text

I. Isolated Testing $PNQPOFOUͷϩδοΫͷΈΛςετ͢Δ

Slide 49

Slide 49 text

I. Isolated Testing @Component({ selector: 'app-root', template: `

{{title}}

My Heroes

  • {{hero.id}} {{hero.name}}
`, }) export class AppComponent { title = 'Tour of Heroes'; heroes: Hero[] = [ { id: 10, name: 'Windstorm' } ]; selectedHero: Hero; onSelect(hero: Hero) { this.selectedHero = hero; } }

Slide 50

Slide 50 text

I. Isolated Testing @Component({ selector: 'app-root', template: `

{{title}}

My Heroes

  • {{hero.id}} {{hero.name}}
`, }) export class AppComponent { title = 'Tour of Heroes'; heroes: Hero[] = [ { id: 10, name: 'Windstorm' } ]; selectedHero: Hero; onSelect(hero: Hero) { this.selectedHero = hero; } }

Slide 51

Slide 51 text

Example: describe('AppComponent(Isolated testing)', () => { it('should be set selectedHero when onSelect called', () => { const comp = new AppComponent(); const hero = { id: 1, name: 'a hero' }; comp.onSelect(hero); expect(comp.selectedHero).toBe(hero); }); });

Slide 52

Slide 52 text

I. Isolated Testing w 5ZQF4DSJQUDMBTTͱͯ͠ͷςετ w 4FSWJDF5FTUJOHͱ΄΅ಉ༷ͷख๏ w $PNQJMF ඳըίετθϩඇৗʹߴ଎ w %0.ؔ࿈ͷݕূ͸Ͱ͖ͳ͍ w ෳࡶͳΠϯελϯεϝιουͷݕূʹ޲͘

Slide 53

Slide 53 text

II. Shallow Testing ࣗ෼ࣗ਎ͷ5FNQMBUFͷΈඳը͢Δ
 Լ૚ͷ$PNQPOFOU͸ඳը͠ͳ͍

Slide 54

Slide 54 text

II. Shallow Testing @Component({ selector: 'app-root', template: `

{{title}}

My Heroes

  • {{hero.id}} {{hero.name}}
`, }) export class AppComponent { title = 'Tour of Heroes'; heroes: Hero[] = [ { id: 10, name: 'Windstorm' } ]; selectedHero: Hero; onSelect(hero: Hero) { this.selectedHero = hero; } }

Slide 55

Slide 55 text

Example: describe('AppComponent(Shallow testing)', () => { it('should render hero-detail element when selectedHero is set', () => { const fixture = TestBed.configureTestingModule({ declarations: [AppComponent], schemas: [NO_ERRORS_SCHEMA], }).createComponent(AppComponent); fixture.componentInstance.selectedHero = { id: 10, name: 'Windstorm' }; fixture.detectChanges(); expect(fixture.debugElement.query(By.css('hero-detail'))).toBeTruthy(); }); });

Slide 56

Slide 56 text

II. Shallow Testing w /0@&33034@4$)&."ʹΑΓԼ૚$PNQPOFOUͷ $PNQJMF͕ແࢹ͞ΕΔ ௨ৗ͸Τϥʔʹͳͬͯ͠·͏ w $PNQJMF ඳըίετ͸ࣗ਎ͷ$PNQPOFOU෼ͷΈ
 ·͊·͊ߴ଎ w ෦෼తʹ%0.ͷݕূ͕Մೳ w )5.-ཁૉͷඳը %0.Πϕϯτϋϯυϥͷݕূ౳ w 5FNQMBUF಺ͷ"OHVMBSFYQSFTTJPO֬ೝʹ޲͘

Slide 57

Slide 57 text

III. Integration Testing Լ૚ͷ$PNQPOFOU΋ؚΊͯશͯඳը͢Δ

Slide 58

Slide 58 text

III. Integration Testing @Component({ selector: 'app-root', template: `

{{title}}

My Heroes

  • {{hero.id}} {{hero.name}}
`, }) export class AppComponent { title = 'Tour of Heroes'; heroes: Hero[] = [ { id: 1, name: 'Windstorm' } ]; selectedHero: Hero; onSelect(hero: Hero) { this.selectedHero = hero; } }

Slide 59

Slide 59 text

Example: describe('AppComponent(Integration Testing)', () => { it('should pass selectedHero object to heroDetailComponent', async(() => { const fixture = TestBed.configureTestingModule({ imports: [AppModule, FormsModule], }).createComponent(AppComponent); fixture.detectChanges(); fixture.debugElement .query(By.css('li:first-child')).triggerEventHandler('click', {}); fixture.detectChanges(); expect( fixture.debugElement.query(By.directive(HeroDetailComponent)) .componentInstance.hero ).toBe(fixture.componentInstance.selectedHero); })); });

Slide 60

Slide 60 text

III. Integration Testing w $PNQPOFOUͷඳըʹඞཁͳґଘؔ܎શͯΛಡΈࠐΉ w શґଘ$PNQPOFOUͷ$PNQJMF ඳըίετΛཁ͢Δ
 ΋ͬͱ΋ߴίετ w ׬શͳ%0.ͷݕূ͕Մೳ w $PNQPOFOU͕ؒ࿈ܞ͢Δ෦෼ͷ֬ೝ౳ʹ޲͘

Slide 61

Slide 61 text

݁ہͲͷύλʔϯ͕ྑ͍ͷ΍Β w 8"$6-Ͱ͸*OUFHSBUJPO5FTUJOH͕ଟΊ w ,BSNB্Ͱݟͨ໨ ಛʹΤοδέʔε ΋֬ೝ͍ͨ͠
 ˞ࣾ಺௨শz,BSNBۦಈ։ൃz w $PNQPOFOUͷߏ੒ʹࡉ͔͍6*$PNQPOFOU͕ඞཁ
 ྫJDPO CVUUPO FUD w 4IBMMPX5FTUJOHͩͱԿ΋ඳը͞Εͳ͍͜ͱ΋ଟ͍ w ࡶʹ.PEVMFΛJNQPSU͢Δํָ͕ ଵຫͱ΋

Slide 62

Slide 62 text

݁ہͲͷύλʔϯ͕ྑ͍ͷ΍Β w $PNQPOFOUʹෳࡶͳϝιουΛ࣮૷͠ͳ͍ํ਑ w ෳࡶ͞͸4FSWJDF 4UPSF૚ ʹدͤΖࢦ਑ͷͨΊ w *TPMBUFE$PNQPOFOU5FTUJOHͷग़൪͕গͳ͍

Slide 63

Slide 63 text

Karma Driven Development

Slide 64

Slide 64 text

Ͳ͜·Ͱݕূ͢Δͷ͔ w ओͳݕূର৅ w OH*G΍ͷӈล͕ਖ਼͘͠ಈ࡞͍ͯ͠Δ͜ͱ w ࢠ$PNQPOFOUͷ!*OQVUʹਖ਼͘͠஋Λ౉͍ͯ͠Δ͜ͱ w %0.Πϕϯτ΍ࢠ$PNQPOFOUͷ!0VUQVUʹԠͯ͡ɺ $PNQPOFOUͷϝιου͕ൃՐ͢Δ͜ͱ w ٯʹςΩετ \\YYY^^ ΍1JQFͷ݁ՌͳͲɺࡉ͔͍ඳը݁Ռ ͸BTTFSUJPO͍ͯ͠ͳ͍ ཧ༝͸ޙड़

Slide 65

Slide 65 text

ࣗಈԽͱճؼςετ "VUPNBUJPO3FHSFTTJPO

Slide 66

Slide 66 text

Put it all together…? w $*Ͱಈ࡞ͤ͞Δ w $PNQJMBUJPO5FTUJOH w "OHVMBS6OJU5FTUJOH

Slide 67

Slide 67 text

…ͨͩճ͚ͩ͢͡Ό໪ମͳ͍

Slide 68

Slide 68 text

One more thing w ൃ୺͸+FTU3FBDUͷ4OBQTIPU5FTUJOH΁ͷಌΕ import React from 'react'; import Link from '../Link.react'; import renderer from 'react-test-renderer'; it('renders correctly', () => { const tree = renderer .create(Facebook) .toJSON(); expect(tree).toMatchSnapshot(); });

Slide 69

Slide 69 text

Snapshot Testing w ςετ݁Ռ 4OBQTIPU Λʮਖ਼͍݁͠Ռʯͱͯ͠อଘ w ࣍ճςετ࣌ʹલճ݁Ռͱͷࠩ෼Λݕࠪ͢Δ ƭ The latest snapshot (DOM String) ƭ The actual snapshot (DOM String) Update if snapshot is accepted Assertion

Slide 70

Slide 70 text

Visual Snapshot Testing w ୯ମςετͰඳըΛ࣮ߦ͍ͯ͠Δ 4IBMMPX*OUFHSBUJPO w ඳը݁Ռಉ࢜ͷൺֱͰ4OBQTIPU5FTUΠέΔ͔΋ʁ Ʃ The latest snapshot (PNG Image) Ʃ The actual snapshot (PNG Image) Update if snapshot is accepted Assertion

Slide 71

Slide 71 text

ಋೖͯ͠Έͨ

Slide 72

Slide 72 text

Expected image Actual Image Difference

Slide 73

Slide 73 text

Flow of Visual Regression Test w $PNQPOFOU5FTUͷBGUFS&BDIͰ,BSNB͔Βը૾Ωϟ ϓνϟΛऔಘ QOHը૾ͱͯ͠อଘ

Slide 74

Slide 74 text

I. Capture Actual Images w ,BSNBʹΑΔ୯ମςετ࣮ߦ w $PNQPOFOU5FTUJOHͷ֤TQFDຖʹ ը໘ΩϟϓνϟΛऔಘ w Ωϟϓνϟऔಘʹ͸ &MFDUSPO /JHIUNBSF ͷ"1*Λར༻ ♥

Slide 75

Slide 75 text

II. Fetch Expected Images w HJUTIPXCSBODIతͳౕ͔Βɺ
 ൺֱର৅ͱ͢Δ΂͖DPNNJUΛ୳ࡧ w ͜ͷDPNNJUIBTIΛLFZʹ"844 ͔Β&YQFDUFEը૾Λμ΢ϯϩʔυ

Slide 76

Slide 76 text

III. Compare w ը૾ͷࠩ෼ݕ஌࣮ߦ JNBHFNBHJDL w "DUVBMࠓճͷςετ݁Ռը૾܈ w &YQFDUFEEPXOMPBEͨ͠ը૾܈ w 4΁ࠓճͷςετը૾ΛΞοϓ w 4΁ൺֱϨϙʔτΛΞοϓ w (JU)VC΁݁ՌΛ௨஌

Slide 77

Slide 77 text

※ ࠩ෼͕ଟ͍ͱ๻ʹౖΒΕ·͢

Slide 78

Slide 78 text

Tools for Visual Regression test w OQNQBDLBHFT TQFDJBMUIBOLTGPS!CPLVXFC w ΩϟϓνϟऔಘLBSNBOJHIUNBSF w ը૾ࠩ෼ݕग़݁ՌϨϙʔτͷग़ྗSFHDMJ w "844(JU)VC"1*DBMM͸TIFMMTDSJQUʹϕλॻ͖ w ݱঢ়͸4FUVQ͕େม
 Ώ͘Ώ͘͸TVJUతͳUPPMʹ͍͖͍ͯͨ͠

Slide 79

Slide 79 text

Visual TestingͷԸܙ w $44TUZMF΍QJQF݁ՌͷݕূΛ໌ࣔతʹॻ͔ͣͱ΋ɺ
 ҙਤͤ͵ഁյʹؾ෇͚Δ w ॳճίϛοτ࣌ͷϨϏϡʔΛ͔ͬ͠Γ͓͚ͯ͠͹Α͍ w ςετ݁Ռ͕ը૾Խ͞Ε͍ͯΔɿ 㾎 ϨϏϡʔ࣌ʹը૾Λ֬ೝͰ͖ΔˠϨϏϡΞෛՙ΋ܰݮ 㾎 ͜ΜͳQOHͰ͖ͨΑʂײ͕ग़Δˠ
 ςετίʔυΛॻ͘ϞνϕʔγϣϯVQʹܨ͕Δ

Slide 80

Slide 80 text

ྫ: ͜ΜͳpngͰ͖ͨΑ(ŪƄźŗ w 4QFDͷ಺༰ lάϥϑʹΧʔιϧ౰ͯͨΒۙ๣఺৘ใ͕QPQVQ͞ΕΔz

Slide 81

Slide 81 text

·ͱΊ /H4VNNBSZ

Slide 82

Slide 82 text

ࠓ೔఻͔͑ͨͬͨ͜ͱ w ੩తղੳπʔϧΛςετʹ׆༻ w 5ZQF4DSJQU "P5$PNQJMF -BOHVBHF4FSWJDF w $PNQPOFOU5FTUJOHQBUUFSOͷ࢖͍෼͚ w *TPMBUFE4IBMMPX*OUFHSBUJPO w νʔϜͰςετΛָ͠ΊΔ࢓૊Έ

Slide 83

Slide 83 text

͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ Have a nice test

Slide 84

Slide 84 text

͓·͚ ओʹۤ࿑࿩ 
 "QQFOEJY

Slide 85

Slide 85 text

A. Component Testͷίετ

Slide 86

Slide 86 text

(ࢀߟ) Component Testͷίετ w *OUFHSBUJPO5FTUJOHQBUUFSO͸݁ߏॏ͍ͨ w $PNQPOFOUTΛؚΉ.PEVMFʹґଘ͢ΔUFTUΛέʔ ε࣮ߦ͢Δͱɺ+J5$PNQJMF͚࣌ؒͩͰdඵఔ౓

Slide 87

Slide 87 text

(࠶ܝ) AoT CompileͷԸܙ w ࣮ߦ࣌ύϑΥʔϚϯε ಛʹॳճඳը࣌ؒ ͷվળ w 5FNQMBUFͷ੩తίʔυνΣοΫ 㾎 "OHVMBS&YQSFTTJPOͷจ๏Τϥʔ 㾎 ଘࡏ͠ͳ͍ϓϩύςΟͷࢀর 㾎 ଘࡏ͠ͳ͍$PNQPOFOU%JSFDUJWF1JQFͷࢀর 㾎 FUD

Slide 88

Slide 88 text

(ࢀߟ) JiT and AoT Unit Testing w "OHVMBSW͔Β͸ɺ"P5$PNQJMFͷ݁ՌΛ୯ମςε τ͔Βར༻Մೳʹ w 4QFDຖͷ$PNQPOFOU$PNQJMF࣌ؒΛ࡟ݮͰ͖Δ // First, initialize the Angular testing environment. getTestBed().initTestEnvironment( BrowserDynamicTestingModule, platformBrowserDynamicTesting(), [()=> AppModuleNgSummary], );

Slide 89

Slide 89 text

(ࢀߟ) ద༻݁Ռ w ࣮1SKͰ͸෼ۙ͘࡟ݮ
 ࠨద༻લ ӈద༻ޙ w ରԠ͢ΔQMVHJOͳͲ͕!BOHVMBSDMJʹ౥ࡌ͞ΕΕ͹ɺ
 ΧδϡΞϧʹར༻Ͱ͖ΔΑ͏ʹͳΔ͸ͣͳͷͰظ଴ɻ

Slide 90

Slide 90 text

B. Visual RegressionͷਏΈ

Slide 91

Slide 91 text

Visual Testingͷେม͞ w ҆ఆͨ͠Ωϟϓνϟऔಘ͸݁ߏେม w ϒϥ΢βͷϨϯμϦϯάΛ଴ͨͳ͍ͱμϝ w ݁ہTFU5JNFPVU NTFD S*$ʹམͪண͘ w ޡݕ஌ 'BMMT1PTJUJWF Λ͍͔ʹݮΒ͔͢ w $44"OJNBUJPO͸ࣄલʹແޮԽ͢ΔͳͲ޻෉͕ඞཁ w * { transition-duration: 0; !important }