Laravel API testen met stubs
Artikel hoe je een stub maakt en gebruikt in een Laravel feature test met een API call. Als je een API wil testen in een feature test wil je niet de echt API aanroepen maar het faken. Dit omdat je niets steeds een API kan/wil aanroepen en het maakt je test sneller.
In dit artikel maak ik gebruik van van een dummy (stub) bestand met daarin de response van een API request. In dit voorbeeld 'stub' ik een Woocommerce product en maak een feature test waarin je zo'n stub bestand kan toepassen.
Stub file maken
Ik gebruik hier zelf een kleine helper functie voor om een dummy/stub bestanden te genereren.<?php
function createTestStub($content, $filename):void {
\Illuminate\Support\Facades\File::put(base_path('tests/Stubs/' . $filename), $content);
}
Ik doe nu een echte API call, als voorbeeld een call om een product van Woocommerce webshop op te halen.
Die data sla ik dan op in een stub bestand om te kunnen gebruiken in een test.
<?php
$response = Http::withBasicAuth('userName', 'passWord')
->baseUrl('https://url-to-woocommerce.com/wp-json/wc/v3/')
->get('products/1914');
if ($response->status() == 200) {
createTestStub($response->body(), 'Woocommerce/TestProducts.json');
}
Route en controller functies om een product op te halen / opslaan<
Hierbij een voorbeeld wat test of we een product vanuit een API call kunnen opslaan in de database.
Route bestand
In mijn route file een post route
<?php Route::post('store-product/{id}', [\App\Http\Controllers\ProductsController::class, 'storeProduct'])->name('storeProduct');
ProductsController, method StoreProduct();
<?php
public function storeProduct(Request $request) { $response = Http::withBasicAuth('userName', 'passWord') ->baseUrl('https://url-to-woocommerce.com/wp-json/wc/v3/')
->get('products/' . $request->get('productId'));
if ($response->status() == 200) {
$product = json_decode($response->body());
// Hier kunnen we nog validatie doen maar dat is weer voor een ander artikel.
return Product::create([
'name' => $product->name,
'slug' => $product->slug,
// hier de rest van het product wat we willen opslaan.
]);
}
return response(json_decode($response->body())->message, $response->status());
}
De feature test
Met onderstaande feature test kunnen we testen of we een product kunnen ophalen en opslaan in onze database.
<?php
namespace Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase; class StoreProductTest extends TestCase {
use RefreshDatabase;
/** * @test */
public function expect_we_can_store_a_product_from_a_woocommerce_api_call_in_our_database() {
$this->post(route('storeProduct'), ['productId' => 1914])
->assertStatus(201);
$this->assertDatabaseCount('wc_products', 1);
$this->assertDatabaseHas('wc_products', [
'name' => 'Product name X',
'slug' => 'product-name-x'
]);
}
}
Als het goed is zal deze test slagen en je deze uitkomst zien na het runnen van deze test.
PASS Tests\Feature\StoreProductTest
✓ expect we can store a product from a woocommerce api call in our database
Tests: 1 passed
Time: 11.31s
Alleen doen we in deze test een echte API call. We moeten nu aangeven in de test dat we de API willen faken met de stub file.
Om API calls te kunnen faken kan je gebruik maken van.
Http::fake
Meer informatie over stubs, fake, mocken enz. kan je vinden in de documentatie van Laravel.
Voor het gebruiken / ophalen van de gemaakte stub bestand heb ik ook een kleine helper functie.
<?php
function getTestStub($fileName): string {
return File::get(base_path('tests/Stubs/' . $fileName));
}
We zitten deze fake HTTP boven in de test en geven aan dat we het gemaakt stub bestand willen gebruiken.
De test zal er nu zo uitzien:
<?php
namespace Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Http;
use Tests\TestCase; class
StoreProductTest extends TestCase {
use RefreshDatabase;
/** * @test */
public function expect_we_can_store_a_product_from_a_woocommerce_api_call_in_our_database() {
Http::fake([ 'https://url-to-woocommerce.com/wp-json/wc/v3/products/1914' => Http::response (
getTestStub('Woocommerce/TestProducts.json')
)]);
$this->post(route('storeProduct'), ['productId' '=' 1914])
->assertStatus(201);
$this->assertDatabaseCount('wc_products', 1);
$this->assertDatabaseHas('wc_products', [
'name' => 'Product name X',
'slug' =>; 'product-name-x'
]);
}
}
De uitkomst is als het goed is hetzelfde, alleen je doet nu geen call meer naar de Woocommerce webshop.