Angular 2 Testing - Chiamata di funzione asincrona - quando usare


89

Quando usi la funzione asincrona nel TestBed durante i test in Angular 2?

Quando lo usi?

 beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [MyModule],
            schemas: [NO_ERRORS_SCHEMA],
        });
    });

E quando lo usi?

beforeEach(async(() => {
    TestBed.configureTestingModule({
        declarations: [MyModule],
        schemas: [NO_ERRORS_SCHEMA],
    });
}));

Qualcuno può illuminarmi su questo?

Risposte:


97

asyncnon consentirà l'avvio del test successivo fino al asynctermine di tutte le sue attività. Quello che asyncfa è avvolgere il callback in una zona, dove setTimeoutvengono tracciate tutte le attività asincrone (ad esempio ). Una volta completate tutte le attività asincrone, il file viene asynccompletato.

Se hai mai lavorato con Jasmine al di fuori di Angular, potresti aver visto doneessere passato al callback

it('..', function(done) {
  someAsyncAction().then(() => {
    expect(something).toBe(something);
    done();
  });
});

Qui, questo è il nativo Jasmine, dove diciamo a Jasmine che questo test dovrebbe ritardare il completamento fino a quando non chiameremo done(). Se non abbiamo chiamato done()e invece abbiamo fatto questo:

it('..', function() {
  someAsyncAction().then(() => {
    expect(something).toBe(something);
  });
});

Il test verrebbe completato anche prima dell'aspettativa, perché la promessa si risolve dopo che il test è terminato eseguendo le attività sincrone.

Con Angular (in un ambiente Jasmine), Angular chiamerà effettivamente donedietro le quinte quando usiamo async. Manterrà traccia di tutte le attività asincrone nella zona e, quando saranno terminate, doneverrà richiamato dietro le quinte.

Nel tuo caso particolare con la TestBedconfigurazione, lo useresti generalmente quando vuoi compileComponents. Raramente mi imbatto in una situazione in cui dovrei chiamarla altrimenti

beforeEach(async(() => {
   TestBed.configureTestingModule({
     declarations: [MyModule],
     schemas: [NO_ERRORS_SCHEMA],
   })
   .compileComponent().then(() => {
      fixture = TestBed.createComponent(TestComponent);
   });
}));

Quando si prova un componente che utilizza templateUrl(se non si utilizza webpack), Angular deve effettuare una richiesta XHR per ottenere il modello, quindi la compilazione del componente sarebbe asincrona. Quindi dovremmo aspettare fino a quando non si risolve prima di continuare i test.


1
Ottima risposta @peeskillet. Solo per assicurarmi di averlo capito: quando hai un modello in linea, asyncnon è necessario. Quando lo usi templateUrl, lo è. Tuttavia, l'inclusione asyncnon "interromperà" un componente del modello inline. Pensi che sia sicuro dire che si può semplicemente usare asyncper impostazione predefinita per ogni test?
vince

2
@vincecampanale Il templateUrl è importante solo durante la configurazione nel file beforeEach. In tal caso è necessario chiamare compileComponents. Non ha nulla a che fare con l'utilizzo asyncsu ogni test se è quello che stai chiedendo. Per quanto riguarda la sicurezza (quando dovresti chiamare compileComponents), vedi Quando dovrei chiamare compileComponents
Paul Samsotha,

2
@vincecampanale Non è sempre il caso di volerlo chiamare prima del test. A volte potresti volerlo chiamare dopo aver eseguito alcune inizializzazioni. Devi capire cosa fa effettivamente chiamarlo. La maggior parte delle volte dovrebbe essere OK. Ma personalmente non mi piace che si siano presi la responsabilità di prendere quella decisione. Ma vedo molte persone che si imbattono nel problema in cui dimenticano di chiamarlo e si chiedono perché qualcosa non funziona. Quindi forse è meglio che generino la chiamata. La posizione potrebbe essere discutibile, ma almeno la chiamano
Paul Samsotha,

2
@vincecampanale Generalmente quando vuoi che la vista (ri) renderizzata è quando dovresti chiamarla. Ad esempio, Crea componente -> visualizzazione rendering. Ma se vuoi inizializzare prima qualcosa come Crea componente -> cambia il valore nel componente utilizzato per il rendering -> visualizza il rendering. Questo è ciò che intendo con forse vuoi inizializzare qualcosa prima
Paul Samsotha

1
Oh e un'altra cosa. La prima volta che lo chiami, è quando ngOnInitviene chiamato il componente. A volte questo è importante durante i test
Paul Samsotha

26

Quando si effettua una chiamata asincrona nel test, la funzione di test effettiva viene completata prima del completamento della chiamata asincrona. Quando è necessario verificare uno stato quando la chiamata è stata completata (che di solito è il caso), il framework di test riporta il test come completato mentre è ancora in corso un lavoro asincrono.

Con l'utilizzo async(...)si dice al framework di test di attendere fino al completamento della promessa di ritorno o dell'osservabile prima di considerare il test completato.

it('should show quote after getQuote promise (async)', async(() => {
  fixture.detectChanges();

  fixture.whenStable().then(() => { // wait for async getQuote
    fixture.detectChanges();        // update view with quote
    expect(el.textContent).toBe(testQuote);
  });
}));

Il codice passato a then(...)verrà eseguito dopo il completamento della funzione di test. Con async()si rende consapevole il framework di test che deve attendere il completamento di promesse e osservabili prima di considerare il test completato.

Guarda anche

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.