2014-10-24 16 views
6

Sto provando a testare la mia implementazione di un gestore webhook Stripe. dati della striscia webhook arriva attraverso il filo come JSON grezzo nel corpo di una richiesta POST, così ho catturare e decodificare i dati in quanto tali:Posso usare il metodo `call` di Laravel per inviare dati JSON grezzi in un test unitario?

public function store() 
{ 
    $input = @file_get_contents("php://input"); 
    $request = json_decode($input); 
    return Json::encode($request); 
} 

Sto tentando di unità di prova di questo codice, ma non posso capire come inviare dati JSON grezzi in un test unitario in modo tale che possa recuperarlo con la funzione file_get_contents("php:input//"). Questo è quello che ho provato (utilizzando PHPUnit):

protected $testRoute = 'api/stripe/webhook'; 

protected $validWebhookJson = <<<EOT 
{ 
    "id": "ch_14qE2r49NugaZ1RWEgerzmUI", 
    "object": "charge", 
    // and a bunch of other fields too 
} 
EOT; 

public function testWebhookDecdoesJsonIntoObject() 
{ 
    $response = $this->call('POST', $this->testRoute, $this->validWebhookJson); // fails because `$parameters` must be an array 
    $response = $this->call('POST', $this->testRoute, [], [], ['CONTENT_TYPE' => 'application/json'], $this->validWebhookJson); 
    dd($response->getData(true)); // array(0) {} BOOOO!!! Where for to my data go? 
} 

Ho anche provato curl ma che avrebbe fatto una richiesta esterna, il che non ha senso per me dal punto di vista unit test. Come posso simulare una richiesta POST con dati JSON grezzi nel corpo che verranno rilevati dal metodo store?

+0

La tecnica nella seconda chiamata sembra corretta per me. Direi che il "mazzo di altri campi" è formattato in modo errato e quindi il json che stai essenzialmente echeggiando è vuoto. Certamente la virgola finale nell'esempio troncato non è json valida. Vorrei iniziare con xdebugging store(). – scipilot

risposta

0

Con Laravel 5.1 è facile inviare JSON, basta passare un normale array PHP e verrà codificato automaticamente. Esempio dalla documentazione:

$this->post('/user', ['name' => 'Sally']) 
     ->seeJson([ 
      'created' => true, 
     ]); 

Dalla documentazione: http://laravel.com/docs/5.1/testing#testing-json-apis

+0

Non penso sia giusto. I documenti dicono che la matrice passata in 'seeJson()' verrà analizzata automaticamente, non nella matrice per il campo dei parametri. Un problema simile è stato sollevato sui problemi di github di Lumen (fondamentalmente Laravel) [qui] (https://github.com/laravel/lumen-framework/issues/149) e un collaboratore regolare degli stati di laravel che devi codificare manualmente. – kidshenlong

4

È possibile. Ma è necessario inviare il JSON codificato come contenuto (cioè corpo della richiesta) e non come parametro.

$this->call(
    'POST', 
    '/articles', 
    [], 
    [], 
    [], 
    $headers = [ 
     'HTTP_CONTENT_LENGTH' => mb_strlen($payload, '8bit'),  
     'CONTENT_TYPE' => 'application/json', 
     'HTTP_ACCEPT' => 'application/json' 
    ], 
    $json = json_encode(['foo' => 'bar']) 
); 

Questo è il settimo parametro.

Se si guarda la definizione del metodo (nel nucleo di Laravel) si dovrebbe essere in grado di vedere cosa si aspetta.

public function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null) 

questo momento non è ancora supportatoper posta laravel 5,1 di, patch, parole, metodi di convenienza di cancellare però.

Questa è l'aggiunta è attualmente in discussione here e here.

MODIFICA: Devo specificare che questa risposta si basa su un'installazione di Laravel 5.1, pertanto potrebbe non essere applicabile al 100% se si utilizza una versione precedente.

+0

Questo è ancora applicabile a Laravel 5.4; tuttavia, l'intestazione deve essere 'CONTENT_TYPE', e non' HTTP_CONTENT_TYPE'. Nota che tutte le altre intestazioni (inclusa l'autorizzazione e cosa no) devono iniziare con 'HTTP_'. – Alex

3

È possibile utilizzare il metodo json descritto qui:

https://laravel.com/api/5.1/Illuminate/Foundation/Testing/TestCase.html#method_json

come si può vedere il terzo parametro è un array di strega dati in questo caso verrà passato al corpo della richiesta come JSON, e se hai bisogno di passare intestazioni extra puoi passarle come array nel quarto parametro.

Esempio: (All'interno della vostra classe di test)

public function testRequestWithJSONBody() 
{ 
    $this->json(
      'POST', //Method 
      '/', //Route 
      ['key1' => 'value1', 'key2' => 'value2'], //JSON Body request 
      ['headerKey1' => 'headerValue1','headerKey2' => 'headerValue2'] // Extra headers (optional) 
     )->seeStatusCode(200); 
} 

Spero che questo aiuti gli altri.

+0

Non è possibile passare una stringa JSON non elaborata con questo approccio, solo un array. – Alex

0

Si potrebbe sovrascrivere il metodo POST in CrawlerTrait: https://laravel.com/api/5.1/Illuminate/Foundation/Testing/CrawlerTrait.html

O creare un nuovo metodo di supporto come la seguente che accetta un argomento opzionale: rawContent

public function postRawContent($uri, array $data = [], array $headers = [], $rawContent = null) 
{ 
    $server = $this->transformHeadersToServerVars($headers); 

    $this->call('POST', $uri, $data, [], [], $server, $rawContent); 

    return $this; 
} 
0

ho voluto mettere alla prova JSON di essere pubblicati dal browser al back-end. Volevo inserire il json grezzo in phpunit, quindi non ho dovuto ricodificare l'array, che ha introdotto degli errori.

Per fare questo ho convertito l'oggetto JSON per una stringa in JavaScript (browser o client) e buttato al registro:

console.log(JSON.stringify(post_data)) 

Avanti ho copiato e incollato che in prova phpunit, poi decodificati esso a un array. Poi ho semplicemente inviato tale matrice a JSON:

$rawContent = '{"search_fields":{"vendor_table_id":"123","vendor_table_name":"","vendor_table_account_number":"","vendor_table_active":"null"},"table_name":"vendor_table"}'; 

$this->json('POST', '/vendors', json_decode($rawContent, true)) 
    ->seeJson([ 
      'id' => 123, 
     ]); 

Questo era l'unico modo che ha funzionato per me, dopo l'attuazione delle altre risposte a questo post, così ho pensato che avrei condiviso. Sto usando laravel 5.

Problemi correlati