Gli "stock" sono un TDD / unità che testano il pattern anti?

6

Da Mock non Stub afferma che Stub fornisce risposte predefinite a chiamate effettuate durante il test, mentre gli oggetti Mock sono preprogrammati con aspettative che formano una specifica delle chiamate che dovrebbero ricevere.
Inoltre diverse fonti affermano che i test non dovrebbero falliti, ma Mock potrebbe .

Che ne pensi di questo:

$validator= $this->getMock('ValidatorService');

        // Set up the expectation for the isValid() method
        // to be called only once and with the string 'textToBeValidated'
        // as its parameter and returns true or false.
        $validator->expects($this->once())
                 ->method('isValid')
                 ->with($this->equalTo('textToBeValidated'))
                 ->will($this->returnValue(true));

Questo è apparso in una revisione del codice in un progetto a cui sto lavorando e l'abbiamo chiamato Stock ( St ub - M ock ). Perchè lo chiedi?!

  1. Imposta un'aspettativa per isValid() di essere chiamato una sola volta e con un determinato input come un Mock.
  2. Restituisce una risposta predefinita come uno Stub.

Ho la sensazione che sia sbagliato, ma cosa succede se usassimo solo uno Stub puro:

 $validator->expects($this->any())  //<-- can't fail the test now
                     ->method('isValid')
                     ->will($this->returnValue(true));   //<-- canned answer
  • Non riesco a verificare che il metodo isValid sia stato chiamato una sola volta con i parametri corretti.
  • Se il test è passato, non sono sicuro che sia passato per il giusto motivo. Forse isValid() è stato chiamato due volte e ha causato il passaggio.

Quindi usiamo un puro Mock invece:

$validator->expects($this->once())
                     ->method('isValid')
                     ->with($this->equalTo('textToBeValidated'))
  • Non riesco a verificare che la mia funzione funzioni correttamente, perché ho verificato solo che la chiamata a isValid() abbia avuto esito positivo. Forse c'è un bug nel resto del mio codice usando ValidatorService .

So che alcune persone parleranno della verifica dello stato e del comportamento, ma per come la vedo io, l'unico modo per essere sicuri che il test passi per il motivo giusto è quello di usare uno Stock (cioè verificare il comportamento e lo stato finale) .

Ovviamente l'altra opzione è scrivere 2 test per ogni criterio di test. Uno usa un Mock e un test identico usando uno Stub. Tuttavia, ciò comporterà un TestOverflow (un numero enorme di test quasi identici).

Qual è il modo corretto per eseguire un test concreto di una funzione utilizzando una dipendenza?

    
posta Songo 03.03.2014 - 17:24
fonte

3 risposte

2

OK Ho fatto delle ricerche e finalmente ho trovato quello che stavo cercando nel post Mazzi per comandi, stub per le query di Mark Seemann .

Per fare una lunga storia breve Azioni sono cattive. Sono un odore di codice o meglio un odore di test unitario.

Avendo provato il dolore di specificare le interazioni tra le classi nel mio codice, trovo "JB Rainsberger" post per riflettere questa brutta verità:

When one uses a mock in place of a stub, one tends to over-specify the collaboration between a Client and its Suppliers, and that leads to brittle tests. These tests tend to make hyperactive assertions, meaning assertions that fail even when the underlying production code works as expected. Such hyperactive assertions play the role of the boy who cried “wolf!”, distracting us with needless concern. Even when these superfluous mocks don’t over-specify a collaboration, they often duplicate specifications in other tests.

Quindi la prossima volta che ti ritrovi a scrivere "aspetta" e "torna" nello stesso oggetto falso ripensateci.

    
risposta data 11.03.2014 - 12:13
fonte
5

Mock restituirà le risposte stub se ciò è richiesto dal contratto della classe / dell'interfaccia che stanno deridendo. Questo è solo necessario. Il tuo oggetto non è niente di speciale, è solo un finto.

Tuttavia, preferisci gli stub alle derisioni quando puoi farla franca. I mock in genere portano a test meno flessibili rispetto ai test senza mock. Ad esempio, devi convalidare che isValid è stato chiamato esattamente una volta? Non puoi invece avere un test case che blocca isValid per restituire true, un altro che stub isValid per restituire falso, e semplicemente osservare i risultati dei due test? (La risposta potrebbe essere "no" se devi assicurarti che il testo corretto sia passato. È solo qualcosa su cui riflettere.)

    
risposta data 03.03.2014 - 17:45
fonte
5

Bene, quello che stai descrivendo come "Stock" è in realtà la definizione di un Mock, almeno nel libro xUnit Patterns , che descrive tutti i principali tipi di duplicati di test.

La logica per i tipi di test raddoppia è che ognuno eredita dal precedente.

Considera un manichino come linea di base, un'implementazione NullObject per ogni interfaccia specificata. Il prossimo tipo è lo stub, che restituisce alcuni valori. Poi c'è la spia, che restituisce i valori proprio come uno stub, ma registra anche i dettagli delle sue interazioni. Poi arriva il Mock, che ereditando dalla Spia, può decidere se fallire un test se l'interazione non è valida per le aspettative date.

Con questa logica, un Mock è una Spia, che è uno Stub, che è un Dummy, che è un Test Double (il concetto completamente astratto). C'è anche il concetto di falsi, ma seguono una gerarchia diversa.

Puoi vedere i dettagli sulla definizione di ciascun tipo qui .

    
risposta data 05.03.2014 - 02:09
fonte

Leggi altre domande sui tag