EventEmitter'ı Angular2'de test etmenin herhangi bir yolu var mı?


88

EventEmitter kullanan bir bileşenim var ve EventEmitter sayfadaki biri tıklandığında kullanılıyor. Bir birim testi sırasında EventEmitter'ı gözlemlememin ve EventEmitter.next () yöntemini tetikleyen öğeyi tıklatıp neyin gönderildiğini görmek için TestComponentBuilder'ı kullanmamın bir yolu var mı?


Neyi denediğinizi gösteren bir plunker sağlayabilir misiniz, o zaman eksik parçaları eklemek için bir göz atabilirim.
Günter Zöchbauer

Yanıtlar:


212

Testiniz şunlar olabilir:

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');
});

bileşeniniz:

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

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

1
Bir düğme yerine tıkladığım bir çapa ise, sorgu seçici sadece düğme yerine bir düğme mi olur? Tam olarak bu bileşene benzer bir şey kullanıyorum, ancak 'wait (değer) .toBe (' merhaba ');' asla kaçmaz. Bunun yerine bir çapa olduğu için mi merak ediyorum.
tallkid24

Cevabımı, gerçek bir yayıcı yerine bir casus kullanarak daha temiz bir test yöntemiyle güncelledim ve işe yaraması gerektiğini düşünüyorum (aslında e-kitabımdaki örnekler için yaptığım şey bu).
cexbrayat

Bu harika çalışıyor, teşekkürler! Ön uç geliştirmede yeniyim, özellikle de birimi test ediyorum. Bu çok yardımcı oluyor. SpyOn işlevinin var olduğunu bile bilmiyordum.
tallkid24

MyComponent'i sarmak için bir TestComponent kullanıyorsanız bunu nasıl test edebilirim? Örneğin html = <my-component (myEventEmitter)="function($event)"></my-component>ve yaptığım testte: tcb.overrideTemplate (TestComponent, html) .createAsync (TestComponent)
bekos

1
mükemmel cevap - çok kısa ve öz - çok kullanışlı bir genel kalıp
danday74

48

Tarzına bağlı olarak bir casus kullanabilirsin. İşte kovulup emitkovulmadığını görmek için bir casusu kolayca nasıl kullanacağınız ...

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

Yanıtı, önceki yorumlarda belirtildiği gibi sorunlu olabilen, async veya fakeAsync'in gereksiz kullanımına karşı güncelledim. Bu cevap, Angular 9.1.7 itibariyle iyi bir çözüm olmaya devam ediyor. Herhangi bir değişiklik olursa, lütfen bir yorum bırakın ve bu cevabı güncelleyeceğim. yorum yapan / moderatörlük yapan herkese teşekkürler.
Joshua Michael Wagoner

expectGerçek casus olmanız gerekmiyor mu ( spyOn()aramanın sonucu )?
Yuri

Spyon'dan sonra "component.buttonClick ()" i kaçırdım. Bu çözüm sorunumu çözdü. Çok teşekkürler!
Pearl

2

Vericiye abone olabilir veya bir @Output()ise, ana şablonda ona bağlanabilir ve bağlamanın güncellenmiş olup olmadığını kontrol edebilirsiniz. Ayrıca bir click olayı gönderebilirsiniz ve ardından aboneliğin tetiklenmesi gerekir.


Yani emitter.subscribe (data => {}); sonraki () çıktıyı nasıl elde ederim?
tallkid24

Kesinlikle. Veya TestComponenthas <my-component (someEmitter)="value=$event">(nerede someEmitterbir @Output()) içindeki şablon, bu durumda öğesinin valueözelliği TextComponentgönderilen olay ile güncellenmelidir.
Günter Zöchbauer

0

Yayınlanan dizinin uzunluğunu test etmem gerekiyordu. Yani bunu diğer Cevapların üstüne böyle yaptım.

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

0

En yüksek oyu alan cevaplar işe yarasa da, iyi test uygulamaları göstermiyorlar, bu yüzden Günter'in cevabını bazı pratik örneklerle genişleteceğimi düşündüm .

Aşağıdaki basit bileşene sahip olduğumuzu düşünelim:

@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!');
  }
}

Bileşen, test edilen sistemdir, parçalarını gözetlemek kapsüllemeyi bozar. Açısal bileşen testleri yalnızca üç şeyi bilmelidir:

  • DOM (örneğin aracılığıyla erişilir fixture.nativeElement.querySelector);
  • @InputS ve @Outputlerin isimleri ; ve
  • İşbirliği hizmetleri (DI sistemi yoluyla enjekte edilir).

Örnekte yöntemlerin doğrudan çağrılmasını veya bileşenin bazı kısımlarında casusluk yapılmasını içeren her şey, uygulama ile çok yakından ilişkilidir ve yeniden düzenlemeye sürtünme katacaktır - test çiftleri yalnızca ortak çalışanlar için kullanılmalıdır. Bu durumda, işbirlikçimiz olmadığı için, herhangi bir alay, casus veya diğer test çiftlerine ihtiyacımız olmamalı .


Bunu test etmenin bir yolu, doğrudan yayıcıya abone olmak ve ardından tıklama eylemini başlatmaktır (bkz. Girişler ve çıkışlar içeren bileşen ):

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!');
  });
});

Bu, doğrudan bileşen örneğiyle etkileşime girse de, adı @Outputgenel API'nin bir parçasıdır, bu nedenle çok sıkı bir şekilde bağlı değildir.


Alternatif olarak, basit bir test ana bilgisayarı oluşturabilir (bkz. Bir test ana bilgisayarı içindeki Bileşen ) ve bileşeninizi fiilen monte edebilirsiniz:

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

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

daha sonra bileşeni bağlam içinde test edin:

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!');
  });
});

componentInstanceBurada Test konak biz aşırı biz aslında test ediyoruz bileşene bağlı değiliz emin olabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.