Angular2 में EventEmitter का परीक्षण करने का कोई तरीका?


88

मेरे पास एक घटक है जो एक EventEmitter का उपयोग करता है और EventEmitter का उपयोग तब किया जाता है जब पृष्ठ पर किसी को क्लिक किया जाता है। क्या कोई तरीका है कि मैं एक इकाई परीक्षण के दौरान EventEmitter का निरीक्षण कर सकता हूं, और TestComponentBuilder का उपयोग करके उस तत्व पर क्लिक कर सकता हूं जो EventEmitter.next () विधि को ट्रिगर करता है और देखें कि क्या भेजा गया था?


क्या आप एक प्लंकर प्रदान कर सकते हैं जो दिखाता है कि आपने क्या प्रयास किया है, तो मुझे लापता टुकड़ों को जोड़ने के लिए एक नज़र हो सकती है।
गुंटर Zöchbauer

जवाबों:


212

आपका परीक्षण हो सकता है:

it('should emit on click', () => {
   const fixture = TestBed.createComponent(MyComponent);
   // spy on event emitter
   const component = fixture.componentInstance; 
   spyOn(component.myEventEmitter, 'emit');

   // trigger the click
   const nativeElement = fixture.nativeElement;
   const button = nativeElement.querySelector('button');
   button.dispatchEvent(new Event('click'));

   fixture.detectChanges();

   expect(component.myEventEmitter.emit).toHaveBeenCalledWith('hello');
});

जब आपका घटक है:

@Component({ ... })
class MyComponent {
  @Output myEventEmitter = new EventEmitter<string>();

  buttonClick() {
    this.myEventEmitter.emit('hello');
  }
}

1
यदि यह एक एंकर है जिसे मैं बटन के बजाय क्लिक कर रहा हूं, तो क्या क्वेरी चयनकर्ता सिर्फ बटन के बजाय होगा? मैं उस घटक की तरह कुछ का उपयोग कर रहा हूँ, लेकिन 'उम्मीद (मान) .toBe (' हैलो ');' कभी नहीं चलता। मुझे आश्चर्य है कि अगर यह एक एंकर है बजाय इसके।
लम्बेकिड 24

मैंने परीक्षण के लिए एक क्लीनर के साथ अपना जवाब अपडेट किया, एक असली एमिटर के बजाय एक जासूस का उपयोग करते हुए, और मुझे लगता है कि यह काम करना चाहिए (यही मैं वास्तव में अपने ईबुक में नमूनों के लिए करता हूं)।
cexbrayat

यह महान काम करता है धन्यवाद! मैं अंत विकास के लिए नया हूं, विशेष रूप से इकाई परीक्षण। इससे बहुत मदद मिलती है। मुझे यह भी नहीं पता था कि स्पाईऑन फ़ंक्शन मौजूद था।
लंबाकीड 24

यदि मैं MyComponent को लपेटने के लिए TestComponent का उपयोग करता हूं, तो मैं यह कैसे परीक्षण कर सकता हूं? उदाहरण के लिए html = <my-component (myEventEmitter)="function($event)"></my-component>और मेरे द्वारा किए जाने वाले परीक्षण में: tcb.overrideTemplate (TestComponent, html) .createAsync (TestComponent)
bekos

1
शानदार जवाब - बहुत संक्षिप्त और इस बिंदु पर - एक बहुत ही उपयोगी सामान्य पैटर्न
danday74

48

आप एक जासूस का उपयोग कर सकते हैं, आपकी शैली पर निर्भर करता है। यहां बताया गया है कि आप जासूसी का इस्तेमाल आसानी से कर सकते हैं कि emitक्या इसे बंद किया जा रहा है ...

it('should emit on click', () => {
    spyOn(component.eventEmitter, 'emit');
    component.buttonClick();
    expect(component.eventEmitter.emit).toHaveBeenCalled();
    expect(component.eventEmitter.emit).toHaveBeenCalledWith('bar');
});

मैंने async या fakeAsync का अनावश्यक उपयोग न करने के उत्तर को अपडेट किया है, जो पिछले टिप्पणियों में बताए अनुसार समस्याग्रस्त हो सकता है। यह उत्तर कोणीय 9.1.7 के रूप में एक अच्छा समाधान है। यदि कुछ भी बदलता है, तो कृपया एक टिप्पणी छोड़ दें और मैं इस उत्तर को अपडेट करूंगा। टिप्पणी / संचालित सभी के लिए धन्यवाद।
जोशुआ माइकल वैगनर

क्या आपको expectवास्तविक जासूस ( spyOn()कॉल का परिणाम ) नहीं होना चाहिए ?
यूरी

मैं "घटक.बटन" () स्पायॉन के बाद याद किया। इस समाधान से मेरी समस्या हल हो गई। आपका बहुत बहुत धन्यवाद!
पर्ल

2

आप emitter के लिए सदस्यता ले सकते हैं या इसे बाँध सकते हैं, यदि यह एक है @Output(), तो मूल टेम्पलेट में और यदि बंधन अद्यतन किया गया था, तो मूल घटक में जाँच करें। आप एक क्लिक ईवेंट भी भेज सकते हैं और फिर सदस्यता को आग लगनी चाहिए।


इसलिए अगर मुझे emitter.subscribe (डेटा => {}) पसंद है; मुझे अगला () आउटपुट कैसे मिलेगा?
लंबाकीड 24

बिल्कुल सही। या में टेम्पलेट TestComponentहै <my-component (someEmitter)="value=$event">(जहां someEmitterएक है @Output()तो) valueकी संपत्ति TextComponentभेजे गए ईवेंट के साथ अद्यतन किया जाना चाहिए।
गुंटर ज़ोचबॉएर

0

मुझे उत्सर्जित सरणी की लंबाई का परीक्षण करने की आवश्यकता थी। तो यह है कि मैंने अन्य उत्तरों के शीर्ष पर यह कैसे किया।

expect(component.myEmitter.emit).toHaveBeenCalledWith([anything(), anything()]);

0

हालांकि उच्चतम मतदान जवाब काम करते हैं, वे अच्छे परीक्षण प्रथाओं का प्रदर्शन नहीं कर रहे हैं, इसलिए मैंने सोचा कि मैं गुंटर के उत्तर पर अपने व्यावहारिक उदाहरणों के साथ विस्तार करूंगा ।

आइए कल्पना करें कि हमारे पास निम्नलिखित सरल घटक हैं:

@Component({
  selector: 'my-demo',
  template: `
    <button (click)="buttonClicked()">Click Me!</button>
  `
})
export class DemoComponent {
  @Output() clicked = new EventEmitter<string>();

  constructor() { }

  buttonClicked(): void {
    this.clicked.emit('clicked!');
  }
}

घटक परीक्षण के तहत प्रणाली है, इसके कुछ हिस्सों पर जासूसी करने से इनकैप्सुलेशन टूट जाता है। कोणीय घटक परीक्षणों को केवल तीन चीजों के बारे में जानना चाहिए:

  • DOM (जैसे के माध्यम से पहुँचा) fixture.nativeElement.querySelector );
  • के नाम @Inputऔर@Output s के ; तथा
  • सहयोगात्मक सेवाएँ (DI प्रणाली के माध्यम से इंजेक्शन)।

कुछ भी जिसमें इंस्टेंस पर सीधे तौर पर इनवॉइस करने के तरीके शामिल हैं या कंपोनेंट के कुछ हिस्सों पर जासूसी को लागू करने के लिए बहुत बारीकी से जोड़ा गया है, और रिफैक्टरिंग के लिए घर्षण को जोड़ देगा - परीक्षण डबल्स केवल सहयोगियों के लिए उपयोग किया जाना चाहिए। इस मामले में, जैसा कि हमारे पास कोई सहयोगी नहीं है, हमें किसी भी नकली, जासूस या अन्य परीक्षण डबल्स की आवश्यकता नहीं होनी चाहिए ।


इसका परीक्षण करने का एक तरीका सीधे एमिटर की सदस्यता लेना है, फिर क्लिक एक्शन को लागू करना ( इनपुट्स और आउटपुट के साथ घटक देखें ):

describe('DemoComponent', () => {
  let component: DemoComponent;
  let fixture: ComponentFixture<DemoComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ DemoComponent ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(DemoComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should emit when clicked', () => {
    let emitted: string;
    component.clicked.subscribe((event: string) => {
      emitted = event;
    });

    fixture.nativeElement.querySelector('button').click();

    expect(emitted).toBe('clicked!');
  });
});

हालांकि यह सीधे घटक उदाहरण के साथ इंटरैक्ट करता है, का नाम है @Output सार्वजनिक एपीआई का हिस्सा है, इसलिए यह बहुत कसकर युग्मित नहीं है।


वैकल्पिक रूप से, आप एक साधारण परीक्षण होस्ट बना सकते हैं (परीक्षण होस्ट के अंदर घटक देखें ) और वास्तव में अपने घटक को माउंट करें:

@Component({
  selector: 'test-host',
  template: `
    <my-demo (clicked)="onClicked($event)"></my-demo>
  `
})
class TestHostComponent {
  lastClick = '';

  onClicked(value: string): void {
    this.lastClick = value;
  }
}

फिर संदर्भ में घटक का परीक्षण करें:

describe('DemoComponent', () => {
  let component: TestHostComponent;
  let fixture: ComponentFixture<TestHostComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ TestHostComponent, DemoComponent ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(TestHostComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should emit when clicked', () => {
    fixture.nativeElement.querySelector('button').click();

    expect(component.lastClick).toBe('clicked!');
  });
});

componentInstanceयहाँ है परीक्षण मेजबान है, तो हम विश्वास है कि हम बहुत ज्यादा घटक हम वास्तव में परीक्षण कर रहे हैं के लिए युग्मित नहीं कर रहे हैं हो सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.