2010-01-20 19 views
13

Sto provando a entrare nel test dell'unità per gli ovvi positivi che introduce, e sto provando a scrivere un test unitario per una classe che ho scritto l'altro giorno. (So ​​che questo è l'opposto di TDD, ti prego di sopportare me)Domanda Test PHPUnit - Come testare la mia classe

La mia classe, Image, viene utilizzata in combinazione con altri per la manipolazione delle immagini.

Image essenzialmente avvolge una risorsa immagine GD e memorizza i dati insieme ad essa. Ad esempio, un'istanza di Image conterrà sempre suo stato attuale, cioè la sua nuova larghezza/altezza se ridimensionata, i dati originali di immagini, ecc

La classe Image contiene inoltre metodi per,

  • Creazione stessa da un file, dati di stringa o URL, ad es $image->loadFromPath()
  • Creazione di una nuova risorsa immagine GD dalle proprietà dell'istanza Image corrente, ad es. per il ridimensionamento delle immagini per mantenere la trasparenza sfondo, ecc
  • Clonare la risorsa immagine GD per l'utilizzo nelle classi di manipolazione

Quello che sto lottando con è come test di unità di questa classe correttamente con PHPUnit. Ho letto alcune letture e ho alcune idee contrastanti su come affrontarle e non so cosa sia giusto. Devo,

  1. scrivere un test per ogni metodo della classe. Ho letto da qualche parte che dovrei testare ogni singolo metodo. Tuttavia, alcuni dei metodi eseguono altri (giustamente, posso aggiungere), quindi avete una catena di dipendenze. Ma ho anche letto che ogni Test unitario dovrebbe essere indipendente dall'altro. Quindi cosa faccio se questo è il caso?
  2. Scrivere ciascun test come percorso di utilizzo della classe. Ho anche letto da qualche parte che ogni test dovrebbe invece rappresentare 1 percorso/percorso di utilizzo che puoi seguire con la classe. Pertanto, se si copre ogni utilizzo, si otterrà la copertura completa del codice.

Quindi, quale di questi è corretto, se presente?

+0

Conosci la copertura del codice? IMO è più importante eseguire ogni riga di codice almeno una volta piuttosto che creare un test per ogni singolo metodo, che non è sempre necessario per la ragione stessa che hai menzionato. – Franz

+0

+1 per entrare in UnitTests – Gordon

+0

So che la copertura del codice è sì, e che dovresti mirare al 100%, ovvero che ogni riga deve essere eseguita almeno una volta. Quindi è sicuramente meglio scrivere il caso di test in cui ogni test è un'azione eseguita dalla classe piuttosto che ogni test per un metodo specifico? –

risposta

8

I test di unità devono essere scritti per valutare l'interfaccia pubblica di una classe. Il tuo test case dovrebbe usare la classe come tu intendi usare nel tuo programma. L'idea qui è di testare il comportamento (sia previsto, inaspettato o condizioni di bordo) della classe.

Entrambe le idee pubblicate sono corrette. In teoria, dovresti avere abbastanza casi di test (percorsi attraverso il tuo codice) che tutti i tuoi metodi nella classe vengano eseguiti.

Come è stato menzionato, la copertura del test del 100% è un obiettivo piacevole, ma non sempre realistico.

Inoltre, nel caso di GD, fare attenzione alla scrittura dei test di unità che testano le funzionalità di GD (è già stato testato, non è necessario sprecare tempo a testarlo di nuovo). Vorrei read up on usando le matrici e gli stub di PHPUnit (e prendendo in giro il filesystem) nel manuale di PHPUnit.

Ecco cosa un test di esempio potrebbe essere simile:

public function testImageIsResized() 
{ 
    $image = new Image(); 
    $image->loadFromPath('some/path'); 
    $image->resize(200, 300); 
    $this->assertEquals(200, $image->getWidth()); 
    $this->assertEquals(300, $image->getHeight()); 
} 

Ora, a seconda del comportamento previsto della classe immagine, questo test potrebbe passare senza problema, oppure potrebbe non riuscire perché si aspettava nuove dimensioni essere proporzionalmente vincolato alle dimensioni dell'immagine originale. Ma non abbiamo chiamato esplicitamente il metodo interno che controlla quel vincolo nel test stesso.

+0

Praticamente i miei pensieri ora! Grazie per il riassunto –

5

È possibile utilizzare covers annotation per specificare se un test copre più metodi. Pertanto, se uno dei tuoi metodi chiama un altro metodo, puoi semplicemente aggiungere l'annotazione al docblock del test e verrà aggiunto alle statistiche sulla copertura del codice, ad es.

/** 
* @test 
* @covers MyClass::something() 
* @covers MyClass::_somethingElse() 
*/ 
public function somethingWorksAsExpected() 
{ 
    $this->assertSame($expected, $this->testObject->something()); 
} 

Per i progetti personali, la copertura del codice 100% va bene. Tuttavia, ho assistito a conferenze a conferenze in cui il 100% è in dubbio necessario. Nonostante tutti i vantaggi, i test richiedono tempo per scrivere e in un progetto a budget potrebbe essere sufficiente testare solo l'80/20 e tralasciare le caratteristiche acriticamente a bassa priorità della tua app.

Per quanto riguarda il test della classe, dai un'occhiata al capitolo Behaviour Driven Development in the PHPUnit Manual. Nel tuo caso, testerei la funzionalità che hai descritto nella tua domanda.

0

Stephen Melrose detto:

Tuttavia, alcuni dei metodi eseguire altri (giustamente Posso aggiungere), in modo da poi dispone di una catena di dipendenza. Ma ho anche letto che ogni test unità dovrebbe essere indipendente dalle altre

indipendenza di prova non è di non testare lo stesso codice per due volte, si tratta di se il risultato (o la mancanza di risultato) di un test colpisce il risultato di un altro. Se il tuo primo test inserisce alcuni dati e poi fallisce prima che possa rimuovere tali dati, il tuo secondo test potrebbe ottenere risultati diversi dal previsto. Idealmente dovresti essere in grado di eseguire i tuoi test in un ordine casuale, o eseguire alcuni e non altri.

Problemi correlati