2016-08-01 7 views
12

का उपयोग करने वाले कोणीय 2 घटकों का परीक्षण करना मेरे पास एक सामान्य, सरल एनजी 2 घटक है जो कुछ डेटा (कैरोसेल आइटम) प्राप्त करने के लिए सेवा कहता है। यह प्रत्येक एन सेकेंड में यूआई में कैरोसेल स्लाइड्स को स्वत: स्विच करने के लिए setInterval का भी उपयोग करता है। यह ठीक काम करता है, लेकिन जब जैस्मीन परीक्षण चलाते हैं तो मुझे त्रुटि मिलती है: "एसिंक परीक्षण क्षेत्र के भीतर से सेट इंटरवल का उपयोग नहीं कर सकता"।सेटिंगरल या सेटटाइमआउट

मैंने इस .zone.runOutsideAngular (() => {...}) में सेट अंतराल कॉल को लपेटने की कोशिश की, लेकिन त्रुटि बनी रही। मैंने सोचा होगा कि फर्जीएसिंक क्षेत्र में चलाने के लिए परीक्षण को बदलने से समस्या हल हो जाएगी, लेकिन फिर मुझे एक त्रुटि मिलती है कि एक्सएचआर कॉल को नकली एसिंक परीक्षण क्षेत्र (जो समझ में आता है) से अनुमति नहीं है।

मैं सेवा और अंतराल द्वारा किए गए दोनों एक्सएचआर कॉल का उपयोग कैसे कर सकता हूं, जबकि अभी भी घटक का परीक्षण करने में सक्षम है? मैं एनजी 2 आरसी 4, कोणीय-क्ली द्वारा उत्पन्न परियोजना का उपयोग कर रहा हूं। अग्रिम में बहुत धन्यवाद।

घटक से मेरे कोड:

constructor(private carouselService: CarouselService) { 
} 

ngOnInit() { 
    this.carouselService.getItems().subscribe(items => { 
     this.items = items; 
    }); 
    this.interval = setInterval(() => { 
     this.forward(); 
    }, this.intervalMs); 
} 

और जैस्मीन कल्पना से:

it('should display carousel items', async(() => { 
    testComponentBuilder 
     .overrideProviders(CarouselComponent, [provide(CarouselService, { useClass: CarouselServiceMock })]) 
     .createAsync(CarouselComponent).then((fixture: ComponentFixture<CarouselComponent>) => { 
      fixture.detectChanges(); 
      let compiled = fixture.debugElement.nativeElement; 
      // some expectations here; 
    }); 
})); 

उत्तर

9

क्लीन कोड का उपयोग करने योग्य कोड का उपयोग करना चाहिए। setInterval कभी-कभी परीक्षण करना मुश्किल होता है क्योंकि समय कभी भी सही नहीं होता है। आपको setTimeout को उस सेवा में सार करना चाहिए जिसे आप परीक्षण के लिए तैयार कर सकते हैं। नकली में आप अंतराल के प्रत्येक टिक को संभालने के लिए नियंत्रण कर सकते हैं। उदाहरण

class IntervalService { 
    interval; 

    setInterval(time: number, callback:() => void) { 
    this.interval = setInterval(callback, time); 
    } 

    clearInterval() { 
    clearInterval(this.interval); 
    } 
} 

class MockIntervalService { 
    callback; 

    clearInterval = jasmine.createSpy('clearInterval'); 

    setInterval(time: number, callback:() => void): any { 
    this.callback = callback; 
    return null; 
    } 

    tick() { 
    this.callback(); 
    } 
} 

के साथ के लिए MockIntervalService अब आप प्रत्येक टिक है, जो इतना अधिक परीक्षण के दौरान के बारे में तर्क करने के लिए आसान है नियंत्रित कर सकते हैं। यह जांचने के लिए एक जासूस भी है कि clearInterval विधि को तब नष्ट किया जाता है जब घटक नष्ट हो जाता है।

आपके CarouselService के लिए, क्योंकि यह भी असीमित है, कृपया this post को अच्छे समाधान के लिए देखें।

नीचे उल्लिखित सेवाओं का उपयोग करके नीचे एक पूर्ण उदाहरण (आरसी 6 का उपयोग कर) है।

import { Component, OnInit, OnDestroy } from '@angular/core'; 
import { CommonModule } from '@angular/common'; 
import { TestBed } from '@angular/core/testing'; 

class IntervalService { 
    interval; 

    setInterval(time: number, callback:() => void) { 
    this.interval = setInterval(callback, time); 
    } 

    clearInterval() { 
    clearInterval(this.interval); 
    } 
} 

class MockIntervalService { 
    callback; 

    clearInterval = jasmine.createSpy('clearInterval'); 

    setInterval(time: number, callback:() => void): any { 
    this.callback = callback; 
    return null; 
    } 

    tick() { 
    this.callback(); 
    } 
} 

@Component({ 
    template: '<span *ngIf="value">{{ value }}</span>', 
}) 
class TestComponent implements OnInit, OnDestroy { 
    value; 

    constructor(private _intervalService: IntervalService) {} 

    ngOnInit() { 
    let counter = 0; 
    this._intervalService.setInterval(1000,() => { 
     this.value = ++counter; 
    }); 
    } 

    ngOnDestroy() { 
    this._intervalService.clearInterval(); 
    } 
} 

describe('component: TestComponent',() => { 
    let mockIntervalService: MockIntervalService; 

    beforeEach(() => { 
    mockIntervalService = new MockIntervalService(); 
    TestBed.configureTestingModule({ 
     imports: [ CommonModule ], 
     declarations: [ TestComponent ], 
     providers: [ 
     { provide: IntervalService, useValue: mockIntervalService } 
     ] 
    }); 
    }); 

    it('should set the value on each tick',() => { 
    let fixture = TestBed.createComponent(TestComponent); 
    fixture.detectChanges(); 
    let el = fixture.debugElement.nativeElement; 
    expect(el.querySelector('span')).toBeNull(); 

    mockIntervalService.tick(); 
    fixture.detectChanges(); 
    expect(el.innerHTML).toContain('1'); 

    mockIntervalService.tick(); 
    fixture.detectChanges(); 
    expect(el.innerHTML).toContain('2'); 
    }); 

    it('should clear the interval when component is destroyed',() => { 
    let fixture = TestBed.createComponent(TestComponent); 
    fixture.detectChanges(); 
    fixture.destroy(); 
    expect(mockIntervalService.clearInterval).toHaveBeenCalled(); 
    }); 
}); 
+0

शानदार, यह वही है जो मुझे जानने की जरूरत है। एक चीज जिसे मुझे बदलने की जरूरत थी वह मॉकइंटरवल सेवा में थी: "कॉलबैक;" दोबारा बुलाना() { }"। अन्यथा इसका परिणाम "TypeError: this.callback एक फ़ंक्शन नहीं है"। बहुत धन्यवाद! –

+1

यह एक अच्छा विचार है और महान काम करता है। यह एक ऐसी सेवा बनाने के लिए और अधिक समझदारी होगी जो सेटटाइम से मेल खाता है और उन्हें स्वैप करने के बजाय अंतराल तर्क सेट करता है। – jsgoupil

+0

इसके अलावा आपके पास उस कोड के साथ दो अंतराल नहीं हो सकते हैं क्योंकि यदि आप उन्हें बाद में साफ़ करना चाहते हैं तो आप उनकी आईडी का ट्रैक खो सकते हैं। इसके लिए मैं अंतराल सेवा को वास्तविक तरीकों की प्रतिलिपि बनाने देता हूं। – Dunos

1

प्रत्यक्ष उपयोग के बारे में क्या? https://github.com/angular/angular/issues/6539 उनका परीक्षण करने के लिए आपको .toPromise() विधि

+0

मैं जो नए कोड लिख रहे हैं, Observable.timer के लिए वास्तव में इस बात की पुष्टि करना चाहते हैं ()/Observable.interval() पसंदीदा विकल्प हो सकता है। किसी भी मामले में अभी भी ऐसी स्थितियां होंगी जहां सेटटाइमआउट/सेट इंटरवल को निपटाया जाना चाहिए। आयातित पुस्तकालयों। –

3

मैं एक ही समस्या थी: विशेष रूप से, इस errror जब किसी अन्य पक्ष को एक परीक्षण से setInterval() बुला रहा था हो रही है:

Error: Cannot use setInterval from within an async zone test.

आप कॉल बाहर नकली कर सकते हैं, लेकिन यह हमेशा वांछनीय नहीं है , क्योंकि आप वास्तव में किसी अन्य मॉड्यूल के साथ बातचीत का परीक्षण करना चाहते हैं।

मैं बस का उपयोग करके मेरे मामले में यह हल चमेली के (> = 2.0) async support बजाय Angulars के async():

it('Test MyAsyncService', (done) => { 
    var myService = new MyAsyncService() 
    myService.find().timeout(1000).toPromise() // find() returns Observable. 
    .then((m: any) => { console.warn(m); done(); }) 
    .catch((e: any) => { console.warn('An error occured: ' + e); done(); }) 
    console.warn("End of test.") 
}); 
संबंधित मुद्दे