Sto lavorando sulla creazione di una suite di test per un PHP Propel progetto utilizzando Phactory e PHPUnit. Attualmente sto provando a testare una funzione che fa una richiesta esterna, e voglio stubare una risposta finta per quella richiesta.Come posso prendere in giro una richiesta Web esterna in PHPUnit?
Ecco un frammento della classe che sto cercando di prova:
class Endpoint {
...
public function parseThirdPartyResponse() {
$response = $this->fetchUrl("www.example.com/api.xml");
// do stuff and return
...
}
public function fetchUrl($url) {
return file_get_contents($url);
}
...
Ed ecco la funzione di test che sto cercando di scrivere.
// my factory, defined in a seperate file
Phactory::define('endpoint', array('identifier' => 'endpoint_$n');
// a test case in my endpoint_test file
public function testParseThirdPartyResponse() {
$phEndpoint = Phactory::create('endpoint', $options);
$endpoint = new EndpointQuery()::create()->findPK($phEndpoint->id);
$stub = $this->getMock('Endpoint');
$xml = "...<target>test_target</target>..."; // sample response from third party api
$stub->expects($this->any())
->method('fetchUrl')
->will($this->returnValue($xml));
$result = $endpoint->parseThirdPartyResponse();
$this->assertEquals('test_target', $result);
}
posso vedere ora, dopo che ho provato il mio codice di prova, che sto creando un oggetto fittizio con getMock
, e poi non utilizzarlo. Quindi la funzione fetchUrl
viene effettivamente eseguita, cosa che non voglio. Ma voglio comunque essere in grado di usare l'oggetto Phactory creato endpoint
, poiché ha tutti i campi corretti popolati dalla mia definizione di fabbrica.
C'è un modo per me di stubare un metodo su un oggetto esistente? Così ho potuto mozzare fetch_url
sull'oggetto $endpoint
Oggetto Endpoint che ho appena creato?
O sto andando tutto sbagliato? c'è un modo migliore per testare l'unità le mie funzioni che si basano su richieste web esterne?
Ho letto la documentazione di PHPUnit riguardante "Stubbing and Mocking Web Services", ma il loro codice di esempio per farlo è lungo 40 righe, senza includere il dover definire il proprio wsdl. Ho difficoltà a credere che questo sia il modo più conveniente per me di gestirlo, a meno che le brave persone di SO non sentano il contrario.
Apprezzo molto qualsiasi aiuto, sono stato appeso su questo tutto il giorno. Grazie!!
Questo è quello che ho finito per fare, anche se non ne sono entusiasta. Una classe addizionale solo per racchiudere 'file_get_contents' _feels_ come overkill per me. È un cambio di codice che farei solo per testarlo, e questo mi fa sentire. Vengo da ruby, che ha la gemma [webmock] (https://github.com/bblimke/webmock/), che fa proprio quello che hai descritto nel tuo ultimo paragrafo: "crea un servizio Web che vive all'interno dei tuoi test e funge da "Mock", restituendo sempre dati preconfigurati ". Invece di programmare che per ora userò il finto percorso degli oggetti. Grazie per i pensieri! – goggin13
Non penso che sia un sovraccarico. Pensaci in questo modo: userai questo codice in molti posti. Tra un anno, c'è un modo migliore di implementare per file_get_contents e devi cambiarlo ovunque. O pensi di voler passare a Buzz (che consiglierei). Nel codice sopra, si inietta l'oggetto e si deve cambiare una chiamata di metodo. Forse è un sovraccarico nel tuo piccolo esempio, ma man mano che la tua applicazione si ingrandisce e potresti voler riutilizzare file_get_contents, potresti apprezzarlo. – Sgoettschkes