Laravel API testen met stubs

Laravel API testen met stubs
published 08-03-2023

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-&gt;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'])-&gt;name('storeProduct');

ProductsController, method StoreProduct();

<?php 

public function storeProduct(Request $request) { $response = Http::withBasicAuth('userName', 'passWord') -&gt;baseUrl('https://url-to-woocommerce.com/wp-json/wc/v3/')
        ->get('products/' . $request-&gt;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' =&gt; 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.

Webbouwplus

Marcel van Doornen - Laravel Freelance developer
Marcel van Doornen, freelance Laravel developer. Ben je benieuwd hoe ik jou kan helpen?
Neem contact met mij op
©2025 Webbouw Plus