2

내 문제를 설명하는 간단한 앱을 만들기 위해 angular-cli를 사용했습니다. 여기에 모든 코드가 표시됩니다. https://github.com/wholladay/tracking서비스를 호출하는 Angular 2 지시문을 테스트하려면 어떻게합니까?

지시문은 포함 된 요소를 클릭 할 때마다 서비스를 호출합니다. 따라서 서비스를 조롱하고 click 이벤트가 지시문에 전송 될 때 서비스가 호출되도록해야합니다. 여기

내 테스트 코드입니다 :

/* tslint:disable:no-unused-variable */ 
import { inject, addProviders } from '@angular/core/testing'; 
import { TestComponentBuilder } from '@angular/compiler/testing'; 
import { Component } from '@angular/core'; 
import { By } from '@angular/platform-browser'; 
import { TrackingDirective } from './tracking.directive'; 
import { TrackingService } from './tracking.service'; 

class MockTrackingService extends TrackingService { 
    public eventCount = 0; 

    public trackEvent(eventName: string) { 
    this.eventCount++; 
    } 
} 

describe('TrackingDirective',() => { 
    let builder: TestComponentBuilder; 
    let mockTrackingService: MockTrackingService; 
    let trackingDirective: TrackingDirective; 

    beforeEach(() => { 
    mockTrackingService = new MockTrackingService(); 
    trackingDirective = new TrackingDirective(mockTrackingService); 
    addProviders([ 
     {provide: TrackingDirective, use: trackingDirective} 
    ]); 
    }); 

    beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { 
    builder = tcb; 
    })); 

    // General button tests 
    it('should apply class based on color attribute', (done:() => void) => { 
    return builder.createAsync(TestApp).then(fixture => { 
     let testComponent = fixture.debugElement.componentInstance; 
     let buttonDebugElement = fixture.debugElement.query(By.css('button')); 

     buttonDebugElement.nativeElement.click(); 
     expect(buttonDebugElement).toBeTruthy(); 
     expect(mockTrackingService.eventCount).toBe(1); 

     done(); 
    }); 
    }); 
}); 

@Component({ 
    selector: 'test', 
    template: `<button tracking="some button"></button>`, 
    directives: [TrackingDirective] 
}) 
class TestApp { 
} 

그리고 여기 내 지시어 코드 : EVENTCOUNT 여전히 0 대신 1이기 때문에 내가 ng test를 통해 테스트를 실행하면

import { Directive, HostListener, Input } from '@angular/core'; 
import { TrackingService } from './tracking.service'; 

@Directive({ 
    selector: '[tracking]', 
    providers: [ 
    TrackingService 
    ] 
}) 
export class TrackingDirective { 

    @Input() tracking: string; 

    constructor(private trackingService: TrackingService) { 
    } 

    @HostListener('click', ['$event.target']) 
    onClick(element) { 
    this.trackingService.trackEvent(this.tracking); 
    } 
} 

테스트가 실패 .

답변

2

대단한 질문입니다! 우리 MockService이 지시어에 우리의 테스트 코드에 주입되어, 우리가 확인해야이 경우

@Directive({ 
    selector: '[tracking]', 
    providers: [ 
    TrackingService 
    ] 
}) 

:

당신은 자신의 제공자의있는 지침을 테스트하기 위해 노력하고 있습니다. eventCount 속성을 확인해야하기 때문에 테스트 코드를 삽입해야합니다. 나는 MockService의 인스턴스를 생성 제안하고 TrackungService의 값으로이 인스턴스를 사용합니다 :

builder 
     .overrideProviders(TrackingDirective, [provide(TrackingService, {useValue: mockService})]) 
     .createAsync(TestApp).then(fixture => { 

... 

     done(); 
    }); 
:

let mockService = new MockTrackingService(); 

beforeEach(() => { 
    addProviders([provide(TrackingService, {useValue: mockService})]); 
}); 

MockService 요구의 같은 인스턴스가 우리의 지침에 대한 공급자로 사용되는

builderoverrideProviders 메서드를 참조하십시오.

그래서 테스트에 대한 전체 코드는 다음과 같습니다

/* tslint:disable:no-unused-variable */ 
import { inject, addProviders } from '@angular/core/testing'; 
import { TestComponentBuilder } from '@angular/compiler/testing'; 
import { Component, provide } from '@angular/core'; 
import { By } from '@angular/platform-browser'; 
import { TrackingDirective } from './tracking.directive'; 
import { TrackingService } from './tracking.service'; 

// do not extend the TrackingService. If there are other 
// dependencies this would be difficult or impossible. 
class MockTrackingService { 
    public eventCount = 0; 

    public trackEvent(eventName: string) { 
    this.eventCount++; 
    } 
} 

let mockService = new MockTrackingService(); 

beforeEach(() => { 
    addProviders([provide(TrackingService, {useValue: mockService})]); 
}); 


describe('TrackingDirective',() => { 
    let builder: TestComponentBuilder; 
    let mockTrackingService: MockTrackingService; 

    beforeEach(inject([TestComponentBuilder, TrackingService], 
    (tcb: TestComponentBuilder, _trackingService: TrackingService) => { 

    builder = tcb; 
    // we need to cast to MockTrackingService because 
    // TrackingService has no eventCount property and we need it 
    mockTrackingService = <MockTrackingService> _trackingService; 

    })); 

    // General button tests 
    it('should apply class based on color attribute', (done:() => void) => { 

    builder 
     .overrideProviders(TrackingDirective, [provide(TrackingService, {useValue: mockService})]) 
     .createAsync(TestApp).then(fixture => { 

     let testComponent = fixture.debugElement.componentInstance; 
     let buttonDebugElement = fixture.debugElement.query(By.css('button')); 

     buttonDebugElement.nativeElement.click(); 

     expect(mockTrackingService.eventCount).toBe(1); 

     done(); 
    }); 
    }); 
}); 

@Component({ 
    selector: 'test', 
    template: `<button tracking="some button"></button>`, 
    directives: [TrackingDirective] 
}) 
class TestApp { 
} 
+0

오, 세상에, 당신이 너무 감사합니다! 나는 내가 가까이에 있다는 것을 알았지 만, 나는 그 마지막 부분을 놓칠 수 없었다. – wholladay