| name | laravel-testing |
| description | Laravel testing with PHPUnit and Dusk, feature tests, unit tests, browser tests, factories, assertions. ALWAYS activate when: writing tests, tests/Feature/, tests/Unit/, tests/Browser/, running php artisan test, test coverage, TDD. Triggers on: test failed, assertion error, factory, seeder, RefreshDatabase, actingAs, mock, Dusk element not found, browser test, screenshot, CI/CD testing, test çalışmıyor, coverage düşük, test hatası, assertion failed, mock çalışmıyor. |
Laravel Testing
PHPUnit + Dusk testing patterns for Laravel 12+.
Feature Tests
<?php
namespace Tests\Feature;
use App\Models\Order;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class OrderTest extends TestCase
{
use RefreshDatabase;
public function test_user_can_create_order(): void
{
$user = User::factory()->create();
$response = $this
->actingAs($user)
->postJson('/api/orders', [
'total' => 100.00,
'items' => [
['product_id' => 1, 'quantity' => 2],
],
]);
$response
->assertCreated()
->assertJsonStructure([
'id',
'status',
'total',
]);
$this->assertDatabaseHas('orders', [
'user_id' => $user->id,
'status' => 'pending',
]);
}
public function test_order_creation_requires_authentication(): void
{
$this->postJson('/api/orders', [])
->assertUnauthorized();
}
public function test_order_validates_required_fields(): void
{
$user = User::factory()->create();
$this
->actingAs($user)
->postJson('/api/orders', [])
->assertUnprocessable()
->assertJsonValidationErrors(['total', 'items']);
}
}
Unit Tests
<?php
namespace Tests\Unit;
use App\Services\TaxCalculator;
use PHPUnit\Framework\TestCase;
class TaxCalculatorTest extends TestCase
{
public function test_calculates_tax_correctly(): void
{
$calculator = new TaxCalculator(taxRate: 0.20);
$result = $calculator->calculate(100.00);
$this->assertEquals(120.00, $result);
}
public function test_zero_amount_returns_zero(): void
{
$calculator = new TaxCalculator(taxRate: 0.20);
$this->assertEquals(0.00, $calculator->calculate(0.00));
}
}
Factories
<?php
namespace Database\Factories;
use App\Enums\OrderStatus;
use App\Models\Order;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class OrderFactory extends Factory
{
public function definition(): array
{
return [
'user_id' => User::factory(),
'status' => OrderStatus::Pending,
'total' => $this->faker->randomFloat(2, 10, 1000),
];
}
public function completed(): static
{
return $this->state(fn (array $attributes) => [
'status' => OrderStatus::Completed,
]);
}
public function cancelled(): static
{
return $this->state(fn (array $attributes) => [
'status' => OrderStatus::Cancelled,
]);
}
}
Factory Usage
$user = User::factory()->create();
$users = User::factory()->count(5)->create();
$order = Order::factory()
->for($user)
->has(OrderItem::factory()->count(3))
->create();
$completedOrder = Order::factory()->completed()->create();
Assertions
$response->assertOk();
$response->assertCreated();
$response->assertNoContent();
$response->assertUnauthorized();
$response->assertForbidden();
$response->assertNotFound();
$response->assertUnprocessable();
$response->assertJson(['status' => 'pending']);
$response->assertJsonPath('data.0.id', 1);
$response->assertJsonCount(3, 'data');
$response->assertJsonStructure(['id', 'name', 'email']);
$this->assertDatabaseHas('orders', ['status' => 'pending']);
$this->assertDatabaseMissing('orders', ['status' => 'cancelled']);
$this->assertDatabaseCount('orders', 5);
$this->assertSoftDeleted($order);
Mocking
use App\Services\PaymentService;
public function test_order_charges_payment(): void
{
$this->mock(PaymentService::class, function ($mock) {
$mock->shouldReceive('charge')
->once()
->with(100.00)
->andReturn(true);
});
}
References
Quick Commands
php artisan test
php artisan test tests/Feature/OrderTest.php
php artisan test --filter=test_user_can_create_order
php artisan test --parallel
php artisan test --coverage --min=80
php artisan test --stop-on-failure