Domanda

Sono per lo più convinti dei benefici di unit testing, e vorrei iniziare ad applicare il concetto di una grande base di codice esistente scritto in PHP. Meno del 10% di tale codice è orientato agli oggetti.

Ho guardato diversi framework di unit test (PHPUnit, SimpleTest, e con PHPT). Tuttavia, non ho trovato esempi per qualsiasi di questi che testare codice procedurale. Qual è il quadro migliore per la mia situazione e ci sono esempi di unità di test PHP utilizzando il codice non-OOP?

È stato utile?

Soluzione

È possibile unit-test PHP procedurale, nessun problema. E tu non sei assolutamente fuori di fortuna se il codice è mescolato con HTML.

A livello di test di applicazione o accettazione, il vostro PHP procedurale probabilmente dipende dal valore delle superglobals ($_POST, $_GET, $_COOKIE, ecc) per determinare il comportamento, e termina includendo un file di modello e sputando l'uscita.

Per fare il test a livello di applicazione, si può solo impostare i valori superglobali; avviare un buffer di uscita (per mantenere un po 'di html da inondazioni schermo); chiamare la pagina; opporre materiale all'interno del buffer; e cestino il buffer alla fine.   Quindi, si potrebbe fare qualcosa di simile:

public function setUp()
{
    if (isset($_POST['foo'])) {
        unset($_POST['foo']);
    }
}

public function testSomeKindOfAcceptanceTest()
{
    $_POST['foo'] = 'bar';
    ob_start();
    include('fileToTest.php');
    $output = ob_get_flush();
    $this->assertContains($someExpectedString, $output);
}

Anche per enormi "quadri" con un sacco di comprende, questo tipo di test vi dirà se si dispone di funzionalità a livello di applicazione di lavoro o meno. Questo sta per essere davvero importante in quanto si inizia a migliorare il codice, perché anche se si è convinti che il connettore del database funziona ancora e sembra meglio di prima, ti consigliamo di cliccare su un pulsante e vedere che, sì, è ancora possibile accesso e uscita attraverso il database.

Ai livelli più bassi, ci sono piccole variazioni portata variabile e se funzioni funzionano effetti collaterali (restituendo vero o falso), o tornare direttamente il risultato.

sono variabili passati in giro in modo esplicito, come parametri o array di parametri tra funzioni? O sono variabili impostate in molti luoghi diversi, e passato implicitamente come globali? Se è la (buona) caso esplicito, è possibile unità di prova una funzione (1) incluso il file che svolge la funzione, quindi (2) che alimenta direttamente i valori dei test di funzionalità, e (3) cattura l'output e affermare contro di essa. Se stai usando globali, devi solo essere molto attenti (come sopra, nell'esempio $ _POST) con attenzione nulli fuori tutte le variabili globali tra test. E 'anche particolarmente utile per mantenere test molto piccoli (5-10 righe, 1-2 afferma) quando si tratta di una funzione che spinge e tira un sacco di variabili globali.

Un altro problema fondamentale è se le funzioni operano restituendo l'uscita, o alterando i params passati in, restituendo vero / falso, invece. Nel primo caso, il test è più facile, ma ancora una volta, è possibile in entrambi i casi:

// assuming you required the file of interest at the top of the test file
public function testShouldConcatenateTwoStringsAndReturnResult()
{
  $stringOne = 'foo';
  $stringTwo = 'bar';
  $expectedOutput = 'foobar';
  $output = myCustomCatFunction($stringOne, $stringTwo);
  $this->assertEquals($expectedOutput, $output);
}

Nel caso in male, in cui il codice funziona da effetti collaterali e restituisce vero o falso, è ancora possibile verificare abbastanza facilmente:

/* suppose your cat function stupidly 
 * overwrites the first parameter
 * with the result of concatenation, 
 * as an admittedly contrived example 
 */
public function testShouldConcatenateTwoStringsAndReturnTrue()
    {
      $stringOne = 'foo';
      $stringTwo = 'bar';
      $expectedOutput = 'foobar';
      $output = myCustomCatFunction($stringOne, $stringTwo);
      $this->assertTrue($output);
      $this->Equals($expectedOutput, $stringOne);
    }

Spero che questo aiuti.

Altri suggerimenti

test di quale unità fanno bene, e ciò che si dovrebbe usarli per, è quando si ha un pezzo di codice che ti danno un numero di ingressi, e si aspetta di ottenere un certo numero di uscite di nuovo fuori. L'essere idea, quando si aggiungono funzionalità in seguito, è possibile eseguire il test e assicurarsi che sia ancora eseguendo la vecchia funzionalità allo stesso modo.

Quindi, se hai un codice-base procedurale, è possibile eseguire questa chiamando le funzioni nei metodi di prova

require 'my-libraries.php';
class SomeTest extends SomeBaseTestFromSomeFramework {
    public function testSetup() {
        $this->assertTrue(true);
    }

    public function testMyFunction() {
        $output = my_function('foo',3);

        $this->assertEquals('expected output',$output);
    }
}

Questo trucco con basi di codice PHP, spesso il vostro codice di biblioteca sarà interferire con il funzionamento del vostro framework di test, come la vostra base di codice e quadri di prova avrà un sacco di codice legato alla creazione di un ambiente applicativo in un browser web ( sessione, le variabili globali condivise, ecc). Aspettatevi di trascorrere qualche tempo di arrivare a un punto in cui è possibile includere il codice di biblioteca e di eseguire un test semplice sporco (la funzione testSetup sopra).

Se il codice non ha funzioni, ed è solo una serie di PHP file che le pagine di output HTML, sei specie di fuori di fortuna. Il tuo codice non può essere separato in unità distinte, il che significa che i test delle unità non sta per essere di grande utilità per voi. Faresti meglio a spendere il vostro tempo a livello di "test di accettazione" con prodotti come Selenio e Watir . Questi vi permetterà di automatizzato un browser, e quindi controllare le pagine per i contenuti specifici luoghi come / in forme.

Si potrebbe cercare di includere il codice non-oop in una classe di test utilizzando

require_once 'your_non_oop_file.php' # Contains fct_to_test()

E con PHPUnit si definisce la funzione di test:

testfct_to_test() {
   assertEquals( result_expected, fct_to_test(), 'Fail with fct_to_test' );
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top