Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ng-japan: Testing Angular app

ng-japan: Testing Angular app

Slides for ng-japan 2017

893f54413c2bd9ba41d11d753aacaf2c?s=128

Yosuke Kurami

June 17, 2017
Tweet

More Decks by Yosuke Kurami

Other Decks in Programming

Transcript

  1. Testing Angular App @Quramy #ng-japan 2017.06.17

  2. About me

  3. About me w גࣜձࣾ8"$6-ॴଐͷϑϩϯτΤϯδχΞ w $PNNVOJUZ w OHKBQBO TUB⒎ 

    w (SBQI2-5PLZP PSHBOJ[FS  w ॻ੶ w ʮ&MFDUSPOͰ͸͡ΊΔΞϓϦ։ൃʯ w झຯ w 7JN5ZQF4DSJQUQMVHJOͷ։ൃϝϯς
  4. Agenda w "OHVMBSͰԿΛ࡞͍ͬͯΔͷ͔ w Ͳ͏΍ͬͯςετͯ͠Δ͔  ੩తղੳฤ  ୯ମςετฤ 

    ࣗಈԽɾճؼςετฤ
  5. ͲΜͳΞϓϦ࡞ͬͯΔͷ

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

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

    MPDఔ౓
  8. γεςϜߏ੒ w 4JOHMF1BHF"QQMJDBUJPO w 'SPOUFOE w 5ZQF4DSJQU"OHVMBS w #BDLFOE w

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

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

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

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

  13. 1. ੩తղੳ Static Analysis

  14. Compile = ࠷ॳͷςετ

  15. Angular and TypeScript w "OHVMBSͱݴ͑͹5ZQF4DSJQU w .JDSPTPGU੡ͷ"MU+4 w ੩తͳܕ෇ WFSVQຖʹݡ͘ͳΔ

    ܕਪ࿦ w $PNQJMF͕௨Βͳ͍ίʔυͳΜͯ࿦֎ͩʂ
  16. Compilation and Templates? w Ͱ΋)5.-ςϯϓϨʔτ͸୞ͷจࣈྻ w ԿΛॻ͍ͯ΋$PNQJMF௨ͬͪΌ͏͡ΌΜʜ import { Component

    } from '@angular/core'; @Component({ selector: 'app-root', template: ` <h1> {{title}} </h1> `, styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'app works!'; } It’s just string literal
  17. AoT Compile w "P5 "IFBEPG5JNF $PNQJMF w ੩తʹ"OHVMBS$PNQPOFOUΛղੳͯ͠
 %0.ૢ࡞ίʔυΛੜ੒͢Δ͜ͱ w

    +J5 +VTUJO5JNF $PNQJMF w ࣮ߦ࣌ʹ$PNQPOFOU͔Β$PNQJMFͯ͠
 %0.ૢ࡞ؔ਺Λ࡞Γग़͢͜ͱ
  18. AoT Compile w "P5$PNQJMF͸5ZQF4DSJQUιʔείʔυΛੜ੒͢Δ hoge.component.ts hoge.component.html hoge.component.css hoge.component.ngfactory.ts AoT Compilation

  19. How to use AoT ? w !BOHVMBSDMJ w !BOHVMBSDPNQJMFSDMJ $

    ng build --prod $ ngc -p tsconfig.json
  20. (ࢀߟ) ݁Ռ͸͜Μͳײ͡

  21. 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<i2.AppComponent> = i1.ɵccf('app-root', i2.AppComponent,View_AppComponent_Host_0,{},{},([] as any[]));
  22. Ε͖ͬͱͨ͠ TypeScript ιʔείʔυ
 (ਓ͕ؒಡΉ΋ͷ͡Όͳ͍͚Ͳ…)

  23. AoT CompileͷԸܙ w ࣮ߦ࣌ύϑΥʔϚϯε ಛʹॳճඳը࣌ؒ ͷվળ w 5FNQMBUFͷ੩తίʔυνΣοΫ 㾎 "OHVMBS&YQSFTTJPOͷจ๏Τϥʔ

    㾎 ଘࡏ͠ͳ͍ϓϩύςΟͷࢀর 㾎 ଘࡏ͠ͳ͍$PNQPOFOU%JSFDUJWF1JQFͷࢀর 㾎 FUD
  24. Make more “strict” w --strictNPEF w 5ZQF4DSJQU͔Βར༻ՄೳͳΦϓγϣϯ w ԼهͷશΦϓγϣϯ͕༗ޮԽ͞ΕΔ --noImplicitAny

    --noImplicitThis --alwaysStrict --strictNullChecks
  25. 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͔΋ΑʁɹͱౖΒΕΔ
  26. Null check example export interface Hoge { foo?: { bar:

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

    string; } } @Component({ selector: 'app-hoge', template: `<div>{{hoge.foo.bar}}</div>`, }) export class HogeComponent { @Input() hoge: Hoge; } ͜Ε͸Ͳ͏ͩΖ͏ʁ
  28. 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͔͍͜͠ʂ
  29. With Angular templates export interface Hoge { foo?: { bar:

    string; } } @Component({ selector: 'app-hoge', template: `<div *ngIf=“hoge.foo”>{{hoge.foo.bar}}</div>`, }) export class HogeComponent { @Input() hoge: Hoge; } ͪΌΜͱOVMMDIFDL͢ΔͱΤϥʔ͸ফ͑Δ
  30. ΋ͬͱૣ͘Τϥʔʹؾ෇͖͍ͨ w ϩʔΧϧ։ൃ࣌͸+J5$PNQJMFΛར༻ͯ͠։ൃ w $*Ͱ"P5Ϗϧυͨ͠ͱ͖ʹΤϥʔʹؾ෇͘ ൵͍͠ʜ

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

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

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

    : "plugins": [ { "name": "@angular/language-service" } ] } }
  34. With VSC

  35. With Vim

  36. Other tools for static analysis w IUUQTQBMBOUJSHJUIVCJPUTMJOU w IUUQTHJUIVCDPNNHFDIFWDPEFMZ[FS

  37. 2. ୯ମςετ
 Unit Testing

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

    +BTNJOF *** "OHVMBSUFTUJOHVUJMJUJFT
  39. I. Karma w 5FTU3VOOFSGPS+BWB4DSJQU w 5FTUDPEFΛϒϥ΢βͰ࣮ߦ͢ΔͨΊͷUPPM w ϒϥ΢βͷىಈ w ςετίʔυͷૹΓࠐΈ

    TFSWFSCSPXTFS  w ςετ݁Ռͷදࣔ CSPXTFSTFSWFS  w FUD
  40. II. Jasmine w 5FTUJOH'SBNFXPSLGPS+BWB4DSJQU w ࠷ॳ͔Β৭ʑೖͬͯΔ w %FTDSJCFTQFDT #%% 

    w "TTFSUJPO  w 4QZJOH  w FUD w /PEFKTPS8FC#SPXTFSͷͲͪΒͰ΋ಈ࡞
  41. 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'); }); });
  42. III. Angular testing utilities w !BOHVMBSDPSFUFTUJOH w ςετ༻"OHVMBSNPEVMFͷηοτΞοϓ  w

    ඇಉظ੍ޚؔ਺  w FUD w ଞʹ΋!BOHVMBSIUUQUFTUJOH΍!BOHVMBSSPVUFS UFTUJOHͳͲɺςετΛαϙʔτ͢Δػೳ܈͕ඪ४Ͱ෇͍ ͯ͘Δ
  43. None
  44. @angular/cli and test w ͔Βςετ͕ಈ࡞͢Δ؀ڥΛ࡞Δ͸݁ߏେมʜ w !BOHVMBSDMJʹ೚ͤΔͷ͕٢ w ,BSNBͷઃఆ XFCQBDLͷઃఆ

    UFTUDPEFͷTDB⒎PME w ͪͳΈʹFFUFTUJOH΋ηοτΞοϓͯ͘͠ΕΔ
  45. 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)
  46. ΍ͬͺΓؾʹͳΔͷ͸ Componentͷςετ

  47. 3 ways to Component Testing w "OHVMBS$PNQPOFOUͷςετύλʔϯ͸େ͖͘௨Γ * *TPMBUFE5FTUJOH **

    4IBMMPX5FTUJOH *** *OUFHSBUJPO5FTUJOH https://vsavkin.com/three-ways-to-test-angular-2-components-dcea8e90bd8d
  48. I. Isolated Testing $PNQPOFOUͷϩδοΫͷΈΛςετ͢Δ

  49. I. Isolated Testing @Component({ selector: 'app-root', template: ` <h1>{{title}}</h1> <h2>My

    Heroes</h2> <ul class="heroes"> <li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li> </ul> <hero-detail [hero]="selectedHero"></hero-detail> `, }) export class AppComponent { title = 'Tour of Heroes'; heroes: Hero[] = [ { id: 10, name: 'Windstorm' } ]; selectedHero: Hero; onSelect(hero: Hero) { this.selectedHero = hero; } }
  50. I. Isolated Testing @Component({ selector: 'app-root', template: ` <h1>{{title}}</h1> <h2>My

    Heroes</h2> <ul class="heroes"> <li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li> </ul> <hero-detail [hero]="selectedHero"></hero-detail> `, }) export class AppComponent { title = 'Tour of Heroes'; heroes: Hero[] = [ { id: 10, name: 'Windstorm' } ]; selectedHero: Hero; onSelect(hero: Hero) { this.selectedHero = hero; } }
  51. 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); }); });
  52. I. Isolated Testing w 5ZQF4DSJQUDMBTTͱͯ͠ͷςετ w 4FSWJDF5FTUJOHͱ΄΅ಉ༷ͷख๏ w $PNQJMF ඳըίετθϩඇৗʹߴ଎

    w %0.ؔ࿈ͷݕূ͸Ͱ͖ͳ͍ w ෳࡶͳΠϯελϯεϝιουͷݕূʹ޲͘
  53. II. Shallow Testing ࣗ෼ࣗ਎ͷ5FNQMBUFͷΈඳը͢Δ
 Լ૚ͷ$PNQPOFOU͸ඳը͠ͳ͍

  54. II. Shallow Testing @Component({ selector: 'app-root', template: ` <h1>{{title}}</h1> <h2>My

    Heroes</h2> <ul class="heroes"> <li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li> </ul> <hero-detail [hero]="selectedHero"></hero-detail> `, }) export class AppComponent { title = 'Tour of Heroes'; heroes: Hero[] = [ { id: 10, name: 'Windstorm' } ]; selectedHero: Hero; onSelect(hero: Hero) { this.selectedHero = hero; } }
  55. 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(); }); });
  56. II. Shallow Testing w /0@&33034@4$)&."ʹΑΓԼ૚$PNQPOFOUͷ $PNQJMF͕ແࢹ͞ΕΔ ௨ৗ͸Τϥʔʹͳͬͯ͠·͏  w $PNQJMF

    ඳըίετ͸ࣗ਎ͷ$PNQPOFOU෼ͷΈ
 ·͊·͊ߴ଎ w ෦෼తʹ%0.ͷݕূ͕Մೳ w )5.-ཁૉͷඳը %0.Πϕϯτϋϯυϥͷݕূ౳ w 5FNQMBUF಺ͷ"OHVMBSFYQSFTTJPO֬ೝʹ޲͘
  57. III. Integration Testing Լ૚ͷ$PNQPOFOU΋ؚΊͯશͯඳը͢Δ

  58. III. Integration Testing @Component({ selector: 'app-root', template: ` <h1>{{title}}</h1> <h2>My

    Heroes</h2> <ul class="heroes"> <li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li> </ul> <hero-detail [hero]="selectedHero"></hero-detail> `, }) export class AppComponent { title = 'Tour of Heroes'; heroes: Hero[] = [ { id: 1, name: 'Windstorm' } ]; selectedHero: Hero; onSelect(hero: Hero) { this.selectedHero = hero; } }
  59. 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); })); });
  60. III. Integration Testing w $PNQPOFOUͷඳըʹඞཁͳґଘؔ܎શͯΛಡΈࠐΉ w શґଘ$PNQPOFOUͷ$PNQJMF ඳըίετΛཁ͢Δ
 ΋ͬͱ΋ߴίετ w

    ׬શͳ%0.ͷݕূ͕Մೳ w $PNQPOFOU͕ؒ࿈ܞ͢Δ෦෼ͷ֬ೝ౳ʹ޲͘
  61. ݁ہͲͷύλʔϯ͕ྑ͍ͷ΍Β w 8"$6-Ͱ͸*OUFHSBUJPO5FTUJOH͕ଟΊ w ,BSNB্Ͱݟͨ໨ ಛʹΤοδέʔε ΋֬ೝ͍ͨ͠
 ˞ࣾ಺௨শz,BSNBۦಈ։ൃz w $PNQPOFOUͷߏ੒ʹࡉ͔͍6*$PNQPOFOU͕ඞཁ


    ྫJDPO CVUUPO FUD  w 4IBMMPX5FTUJOHͩͱԿ΋ඳը͞Εͳ͍͜ͱ΋ଟ͍ w ࡶʹ.PEVMFΛJNQPSU͢Δํָ͕ ଵຫͱ΋
  62. ݁ہͲͷύλʔϯ͕ྑ͍ͷ΍Β w $PNQPOFOUʹෳࡶͳϝιουΛ࣮૷͠ͳ͍ํ਑ w ෳࡶ͞͸4FSWJDF 4UPSF૚ ʹدͤΖࢦ਑ͷͨΊ w *TPMBUFE$PNQPOFOU5FTUJOHͷग़൪͕গͳ͍

  63. Karma Driven Development

  64. Ͳ͜·Ͱݕূ͢Δͷ͔ w ओͳݕূର৅ w OH*G΍<DMBTTYYYY>ͷӈล͕ਖ਼͘͠ಈ࡞͍ͯ͠Δ͜ͱ w ࢠ$PNQPOFOUͷ!*OQVUʹਖ਼͘͠஋Λ౉͍ͯ͠Δ͜ͱ w %0.Πϕϯτ΍ࢠ$PNQPOFOUͷ!0VUQVUʹԠͯ͡ɺ $PNQPOFOUͷϝιου͕ൃՐ͢Δ͜ͱ

    w ٯʹςΩετ \\YYY^^ ΍1JQFͷ݁ՌͳͲɺࡉ͔͍ඳը݁Ռ ͸BTTFSUJPO͍ͯ͠ͳ͍ ཧ༝͸ޙड़
  65. ࣗಈԽͱճؼςετ "VUPNBUJPO3FHSFTTJPO

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

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

  68. One more thing w ൃ୺͸+FTU 3FBDUͷ4OBQTIPU5FTUJOH΁ͷಌΕ import React from 'react';

    import Link from '../Link.react'; import renderer from 'react-test-renderer'; it('renders correctly', () => { const tree = renderer .create(<Link page="http://www.facebook.com">Facebook</Link>) .toJSON(); expect(tree).toMatchSnapshot(); });
  69. Snapshot Testing w ςετ݁Ռ 4OBQTIPU Λʮਖ਼͍݁͠Ռʯͱͯ͠อଘ w ࣍ճςετ࣌ʹલճ݁Ռͱͷࠩ෼Λݕࠪ͢Δ ƭ The

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

    The latest snapshot (PNG Image) Ʃ The actual snapshot (PNG Image) Update if snapshot is accepted Assertion
  71. ಋೖͯ͠Έͨ

  72. Expected image Actual Image Difference

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

  74. I. Capture Actual Images w ,BSNBʹΑΔ୯ମςετ࣮ߦ w $PNQPOFOU5FTUJOHͷ֤TQFDຖʹ ը໘ΩϟϓνϟΛऔಘ w

    Ωϟϓνϟऔಘʹ͸ &MFDUSPO /JHIUNBSF ͷ"1*Λར༻ ♥
  75. II. Fetch Expected Images w HJUTIPXCSBODIతͳౕ͔Βɺ
 ൺֱର৅ͱ͢Δ΂͖DPNNJUΛ୳ࡧ w ͜ͷDPNNJUIBTIΛLFZʹ"844 ͔Β&YQFDUFEը૾Λμ΢ϯϩʔυ

  76. III. Compare w ը૾ͷࠩ෼ݕ஌࣮ߦ JNBHFNBHJDL  w "DUVBMࠓճͷςετ݁Ռը૾܈ w &YQFDUFEEPXOMPBEͨ͠ը૾܈

    w 4΁ࠓճͷςετը૾ΛΞοϓ w 4΁ൺֱϨϙʔτΛΞοϓ w (JU)VC΁݁ՌΛ௨஌
  77. ※ ࠩ෼͕ଟ͍ͱ๻ʹౖΒΕ·͢

  78. Tools for Visual Regression test w OQNQBDLBHFT TQFDJBMUIBOLTGPS!CPLVXFC  w

    ΩϟϓνϟऔಘLBSNBOJHIUNBSF w ը૾ࠩ෼ݕग़݁ՌϨϙʔτͷग़ྗSFHDMJ w "844(JU)VC"1*DBMM͸TIFMMTDSJQUʹϕλॻ͖ w ݱঢ়͸4FUVQ͕େม
 Ώ͘Ώ͘͸TVJUతͳUPPMʹ͍͖͍ͯͨ͠
  79. Visual TestingͷԸܙ w $44TUZMF΍QJQF݁ՌͷݕূΛ໌ࣔతʹॻ͔ͣͱ΋ɺ
 ҙਤͤ͵ഁյʹؾ෇͚Δ w ॳճίϛοτ࣌ͷϨϏϡʔΛ͔ͬ͠Γ͓͚ͯ͠͹Α͍ w ςετ݁Ռ͕ը૾Խ͞Ε͍ͯΔɿ 㾎

    ϨϏϡʔ࣌ʹը૾Λ֬ೝͰ͖ΔˠϨϏϡΞෛՙ΋ܰݮ 㾎 ͜ΜͳQOHͰ͖ͨΑʂײ͕ग़Δˠ
 ςετίʔυΛॻ͘ϞνϕʔγϣϯVQʹܨ͕Δ
  80. ྫ: ͜ΜͳpngͰ͖ͨΑ(ŪƄźŗ w 4QFDͷ಺༰ lάϥϑʹΧʔιϧ౰ͯͨΒۙ๣఺৘ใ͕QPQVQ͞ΕΔz

  81. ·ͱΊ /H4VNNBSZ

  82. ࠓ೔఻͔͑ͨͬͨ͜ͱ w ੩తղੳπʔϧΛςετʹ׆༻ w 5ZQF4DSJQU "P5$PNQJMF -BOHVBHF4FSWJDF  w $PNQPOFOU5FTUJOHQBUUFSOͷ࢖͍෼͚

    w *TPMBUFE4IBMMPX*OUFHSBUJPO w νʔϜͰςετΛָ͠ΊΔ࢓૊Έ
  83. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ Have a nice test

  84. ͓·͚ ओʹۤ࿑࿩ 
 "QQFOEJY

  85. A. Component Testͷίετ

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

  87. (࠶ܝ) AoT CompileͷԸܙ w ࣮ߦ࣌ύϑΥʔϚϯε ಛʹॳճඳը࣌ؒ ͷվળ w 5FNQMBUFͷ੩తίʔυνΣοΫ 㾎

    "OHVMBS&YQSFTTJPOͷจ๏Τϥʔ 㾎 ଘࡏ͠ͳ͍ϓϩύςΟͷࢀর 㾎 ଘࡏ͠ͳ͍$PNQPOFOU%JSFDUJWF1JQFͷࢀর 㾎 FUD
  88. (ࢀߟ) JiT and AoT Unit Testing w "OHVMBSW͔Β͸ɺ"P5$PNQJMFͷ݁ՌΛ୯ମςε τ͔Βར༻Մೳʹ w

    4QFDຖͷ$PNQPOFOU$PNQJMF࣌ؒΛ࡟ݮͰ͖Δ // First, initialize the Angular testing environment. getTestBed().initTestEnvironment( BrowserDynamicTestingModule, platformBrowserDynamicTesting(), [()=> AppModuleNgSummary], );
  89. (ࢀߟ) ద༻݁Ռ w ࣮1SKͰ͸෼ۙ͘࡟ݮ
 ࠨద༻લ ӈద༻ޙ  w ରԠ͢ΔQMVHJOͳͲ͕!BOHVMBSDMJʹ౥ࡌ͞ΕΕ͹ɺ
 ΧδϡΞϧʹར༻Ͱ͖ΔΑ͏ʹͳΔ͸ͣͳͷͰظ଴ɻ

  90. B. Visual RegressionͷਏΈ

  91. Visual Testingͷେม͞ w ҆ఆͨ͠Ωϟϓνϟऔಘ͸݁ߏେม w ϒϥ΢βͷϨϯμϦϯάΛ଴ͨͳ͍ͱμϝ w ݁ہTFU5JNFPVU NTFD 

    S*$ʹམͪண͘ w ޡݕ஌ 'BMMT1PTJUJWF Λ͍͔ʹݮΒ͔͢ w $44"OJNBUJPO͸ࣄલʹແޮԽ͢ΔͳͲ޻෉͕ඞཁ w * { transition-duration: 0; !important }