È una cattiva pratica che i test unitari siano dipendenti l'uno dall'altro?

8

Diciamo che ho una sorta di unit test come questo:

let myApi = new Api();

describe('api', () => {

  describe('set()', () => {
    it('should return true when setting a value', () => {
      assert.equal(myApi.set('foo', 'bar'), true);
    });
  });

  describe('get()', () => {
    it('should return the value when getting the value', () => {
      assert.equal(myApi.get('foo'), 'bar');
    });
  });

});

Quindi ora ho 2 test unitari. Uno imposta un valore in un'API. L'altro verifica per assicurarsi che venga restituito il valore corretto. Tuttavia il secondo test dipende dal primo. Dovrei aggiungere un metodo .set() nel 2 ° test prima di get() con il solo scopo di assicurarmi che il secondo test non dipenda da altro?

Inoltre, in questo esempio dovrei creare un'istanza di myApi per ogni test invece di farlo una volta prima dei test?

    
posta Jake Wilson 05.11.2016 - 01:34
fonte

2 risposte

15

Sì, è una cattiva pratica. I test unitari devono essere eseguiti indipendentemente l'uno dall'altro, per gli stessi motivi per cui è necessario eseguire altre funzioni indipendentemente: puoi trattarlo come un'unità indipendente.

Should I add in a .set() method in the 2nd test before the get() with the sole purpose of making sure the 2nd test is not dependent on anything else?

Sì. Tuttavia, se questi sono solo metodi getter e setter nudi, non contengono alcun comportamento e non dovresti davvero aver bisogno di testarli, a meno che tu non abbia una reputazione per le cose fat-fingering in modo tale che il getter / setter compila ma imposta o ottiene il campo sbagliato.

    
risposta data 05.11.2016 - 01:39
fonte
2

Cerca di seguire la struttura di assetto-atto-assert per ogni test.

  1. Disporre i tuoi oggetti ecc. e metterli in uno stato noto (un dispositivo di prova). A volte, questa fase include affermazioni per dimostrare che sei effettivamente nello stato che pensi di essere.
  2. Agisci, ovvero: esegui il comportamento che stai testando.
  3. Asserisci di aver ottenuto il risultato previsto.

I test non si preoccupano di creare prima uno stato conosciuto, quindi sono privi di significato isolati.

Inoltre, i test unitari non testano necessariamente un solo metodo - i test unitari dovrebbero testare un'unità. Di solito, questa unità è una classe. Alcuni metodi come get() hanno senso solo in combinazione con un altro.

Il collaudo di getter e setter è ragionevole, in particolare nei linguaggi dinamici (solo per assicurarsi che siano effettivamente lì). Per testare un getter, dobbiamo prima fornire un valore conosciuto. Questo potrebbe accadere attraverso il costruttore o attraverso un setter. O visto in modo diverso: testare il getter è implicito nei test del setter e del costruttore. E il setter, restituisce sempre true , o solo quando il valore è stato cambiato? Questo potrebbe portare ai seguenti test (pseudocodice):

describe Api:

  it has a default value:
    // arrange
    api = new Api()
    // act & assert
    assert api.get() === expected default value

  it can take custom values:
    // arrange & act
    api = new Api(42)
    // act & assert
    assert api.get() === 42

  describe set:

    it can set new values:
      // arrange
      api = new Api(7)
      // act
      ok = api.set(13)
      // assert
      assert ok === true:
      assert api.get() === 13

    it returns false when value is unchanged:
      // arrange
      api = new Api(57)
      // act
      ok = api.set(57)
      // assert
      assert ok === false
      assert api.get() === 57

Riutilizzare lo stato di un test precedente renderebbe i nostri test abbastanza fragili. Riordinare i test o modificare il valore esatto in un test potrebbe causare il fallimento di test apparentemente non correlati. Supponendo che uno stato specifico possa anche nascondere i bug, se causa il superamento dei test, questo dovrebbe effettivamente fallire. Per evitare ciò, alcuni runner di test hanno opzioni per eseguire i test case in un ordine casuale.

Tuttavia, ci sono casi in cui riutilizziamo lo stato fornito dal test precedente. In particolare, quando la creazione di un dispositivo di prova richiede molto tempo, combiniamo molti casi di test in una suite di test. Sebbene questi test siano più fragili, potrebbero essere ancora più preziosi ora perché possono essere eseguiti più rapidamente e più spesso. In pratica, la combinazione di test è auspicabile ogni volta che i test coinvolgono un componente manuale, quando è necessario un database di grandi dimensioni o quando si testano le macchine a stati.

    
risposta data 05.11.2016 - 15:45
fonte

Leggi altre domande sui tag