Pest Test mit Migration und Seed für ein Laravel-Projekt
von Andreas
Migration erstellen
Führe im Terminal den Befehl aus, um eine Migration zu erstellen:
php artisan make:migration create_products_table
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProductsTable extends Migration
{
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->decimal('price', 8, 2);
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('products');
}
}
In der generierten Datei (z. B. database/migrations/xxxx_xx_xx_create_products_table.php) definierst du die Tabelle:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProductsTable extends Migration
{
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->decimal('price', 8, 2);
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('products');
}
}
Danach führst du die Migration aus:
php artisan migrate
Seed erstellen
Führe diesen Befehl aus, um einen Seeder zu erstellen:
php artisan make:seeder ProductSeeder
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class ProductSeeder extends Seeder
{
public function run()
{
DB::table('products')->insert([
['name' => 'Product 1', 'price' => 19.99],
['name' => 'Product 2', 'price' => 29.99],
['name' => 'Product 3', 'price' => 39.99],
]);
}
}
Führe den Seeder aus:
php artisan db:seed --class=ProductSeeder
Pest Test erstellen
Erstelle eine neue Pest-Testdatei:
php artisan make:test ProductTest
Bearbeite die Datei, z. B. tests/Feature/ProductTest.php:
use App\Models\Product;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('checks if seeded products exist', function () {
// Seed the database
$this->seed(\Database\Seeders\ProductSeeder::class);
// Assert that products are in the database
$this->assertDatabaseCount('products', 3);
$this->assertDatabaseHas('products', ['name' => 'Product 1', 'price' => 19.99]);
$this->assertDatabaseHas('products', ['name' => 'Product 2', 'price' => 29.99]);
$this->assertDatabaseHas('products', ['name' => 'Product 3', 'price' => 39.99]);
});
it('creates a new product', function () {
// Create a product
$product = Product::create([
'name' => 'New Product',
'price' => 49.99,
]);
// Assert the product was created
$this->assertDatabaseHas('products', ['name' => 'New Product', 'price' => 49.99]);
});
Test ausführen
Führe den Test mit Pest aus:
./vendor/bin/pest
Du solltest eine Ausgabe wie diese sehen:
PASS Tests\Feature\ProductTest
✓ checks if seeded products exist
✓ creates a new product
Wann beforeAll verwenden?
Nutze beforeAll, wenn du teure Operationen (z. B. komplexe Setup-Schritte) nur einmal ausführen möchtest, und diese für alle Tests in der Datei gültig bleiben sollen. Für Datenbanktests ist es besser, RefreshDatabase direkt mit uses zu kombinieren, um die Testisolierung zu gewährleisten.
Nein, es gibt kein $this in einem beforeAll-Block in Pest. Das liegt daran, dass beforeAll außerhalb des Kontextes eines Tests ausgeführt wird, und $this in Pest normalerweise nur innerhalb von Tests verfügbar ist, da es den Testfall selbst repräsentiert.
Warum $this nicht in beforeAll?
$thisverweist in PHPUnit- und Pest-Tests auf die Instanz des Testfalls.- Ein
beforeAllwird nur einmal pro Datei ausgeführt, während$thisauf jeden Testfall (jede Testmethode) angewendet wird. - Pest führt
beforeAllin einem statischen Kontext aus, was bedeutet, dass es keinen direkten Zugriff auf die Instanz gibt.
