Testing
Marko uses Pest PHP for testing and provides a marko/testing package with fakes for all major services.
composer require --dev marko/testingRunning Tests
Section titled “Running Tests”# Run all tests./vendor/bin/pest --parallel
# Run with coverage./vendor/bin/pest --parallel --coverage --min=80
# Run a specific test file./vendor/bin/pest tests/Feature/PostTest.phpWriting Tests
Section titled “Writing Tests”Pest tests are expressive and concise:
<?php
declare(strict_types=1);
use App\Blog\Service\PostService;use Marko\Testing\Fake\FakeEventDispatcher;
test('creates a post and dispatches event', function () { $events = new FakeEventDispatcher(); $service = new PostService(events: $events);
$post = $service->createPost('Hello', 'World');
expect($post->title)->toBe('Hello') ->and($post->body)->toBe('World');
$events->assertDispatched(PostCreatedEvent::class);});Available Fakes
Section titled “Available Fakes”The marko/testing package provides test doubles for all major interfaces:
| Fake | Replaces |
|---|---|
FakeEventDispatcher | EventDispatcherInterface |
FakeMailer | MailerInterface |
FakeQueue | QueueInterface |
FakeSession | SessionInterface |
FakeCookieJar | CookieJarInterface |
FakeLogger | LoggerInterface |
FakeConfigRepository | ConfigRepositoryInterface |
FakeAuthenticatable | AuthenticatableInterface |
FakeUserProvider | UserProviderInterface |
Each fake has assertXxx() methods for verifying behavior:
$mailer = new FakeMailer();
// ... code that sends mail
$mailer->assertSent(WelcomeEmail::class);$mailer->assertSentCount(1);Custom Pest Expectations
Section titled “Custom Pest Expectations”Marko auto-loads custom expectations for cleaner assertions:
// Instead of: $events->assertDispatched(PostCreatedEvent::class)expect($events)->toHaveDispatched(PostCreatedEvent::class);
// Instead of: $mailer->assertSent(WelcomeEmail::class)expect($mailer)->toHaveSent(WelcomeEmail::class);
// Instead of: $queue->assertPushed(SendEmail::class)expect($queue)->toHavePushed(SendEmail::class);
// Instead of: $logger->assertLogged('info', 'message')expect($logger)->toHaveLogged('info', 'message');Testing with FakeConfigRepository
Section titled “Testing with FakeConfigRepository”Pass a flat dot-notation array:
$config = new FakeConfigRepository([ 'auth.defaults.guard' => 'web', 'auth.guards.web.driver' => 'session',]);
$service = new AuthService(config: $config);Test Naming Conventions
Section titled “Test Naming Conventions”Marko tests use present tense, concise names:
// Goodtest('creates a post with valid data', function () { /* ... */ });test('throws when title is empty', function () { /* ... */ });
// Avoidtest('it should be able to demonstrate creating a post', function () { /* ... */ });Next Steps
Section titled “Next Steps”- Error Handling — test error scenarios
- Authentication — test auth flows with fakes
- Testing package reference — full API details