PHP code example of tyloo / atc

1. Go to this page and download the library: Download tyloo/atc library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

tyloo / atc example snippets


final class CreateUserTest extends ApiTestCase
{
    use Factories;
    use ResetDatabase;
    use InteractsWithDatabase;
    use InteractsWithMessenger;

    #[Test]
    public function admin_creates_a_user_and_queues_welcome_email(): void
    {
        $admin = AdminFactory::createOne();

        $this->actingAs($admin)
            ->post('/api/users', json: [
                'email' => '[email protected]',
                'name'  => 'Jean Bond',
            ])
            ->assertStatus(201)
            ->assertMatchesJsonSchema('users/create.json')
            ->assertJsonPath('data.email', '[email protected]')
            ->assertHeader('Location', '/api/users/42');

        $this->assertDatabaseHas(User::class, ['email' => '[email protected]']);
        $this->assertMessageDispatched(
            SendWelcomeEmail::class,
            fn (SendWelcomeEmail $m) => $m->email === '[email protected]',
        );
    }
}

$this->get('/api/users');
$this->post('/api/users', json: ['name' => 'Alice']);
$this->patch('/api/users/1', json: ['name' => 'Bob']);
$this->put('/api/users/1', json: [...]);
$this->delete('/api/users/1');

$this->get('/api/users',
    headers: ['X-Tenant' => 'acme'],
    query:   ['filter' => 'active', 'page' => 2],
);

$this->post('/api/login', formData: ['username' => 'a', 'password' => 'b']);
$this->post('/api/uploads', files: ['file' => $uploadedFile]);

$this->withHeaders(['Accept-Language' => 'fr'])
    ->get('/api/users')
    ->assertJsonContains(['greeting' => 'Bonjour']);

$this->get('/api/products')->assertStatusOk(); // still sends Accept-Language: fr

$this->get('/api/users/42')
    ->assertStatusOk()                          // 200
    ->assertHeader('Content-Type', 'application/json')
    ->assertJsonContains(['id' => 42, 'name' => 'Alice'])
    ->assertJsonPath('roles[0]', 'admin');

$response->assertStatus(200); // exact match
$response->assertStatusOk();  // shorthand for the common case

$response->assertHeader('Content-Type', 'application/json');
$response->assertHeaderHas('ETag');         // present, value irrelevant
$response->assertHeaderMissing('X-Debug-Token');

$response->assertJson([
    'id'   => 1,
    'name' => 'Alice',
]);

$response->assertJsonContains([
    'data' => ['email' => '[email protected]'],
]);

$body = $response->json();                  // decoded array
$email = $response->json('data.email');     // JMESPath expression

$status = $response->statusCode();          // int
$body   = $response->content();             // raw string
$ms     = $response->responseTimeMs();      // float
$raw    = $response->raw();                 // Symfony Response

$response = $this->lastResponse();          // last response from this test

$response
    ->assertJsonPath('user.email', '[email protected]')
    ->assertJsonPath('data[0].active', true)
    ->assertJsonPath('roles | length(@)', 3);

$response->assertJsonPath('id', fn ($v) => is_int($v) && $v > 0);

$response->assertJsonMissingPath('deleted_at');
$response->assertJsonCount(3, 'data');
$response->assertJsonCount(2);              // root must be an array of 2

$this->post('/api/users', json: [...])
    ->assertStatus(201)
    ->assertMatchesJsonSchema('users/create.json');

$this->get('/api/heavy-report')
    ->assertStatusOk()
    ->assertResponseTimeLessThan(500)       // < 500 ms
    ->assertResponseTimeBetween(50, 500);   // sanity bounds (catch suspiciously-fast cached responses)

$this->withToken('eyJhbGciOi...')->get('/api/me')->assertStatusOk();

// custom scheme
$this->withToken('xxx', scheme: 'Basic')->get('/api/me');

use App\Factory\UserFactory;
use Tyloo\Atc\ApiTestCase;
use Zenstruck\Foundry\Test\Factories;
use Zenstruck\Foundry\Test\ResetDatabase;

final class ProfileTest extends ApiTestCase
{
    use Factories;
    use ResetDatabase;

    #[Test]
    public function returns_authenticated_users_profile(): void
    {
        $alice = UserFactory::createOne(['email' => '[email protected]']);

        $this->actingAs($alice)
            ->get('/api/me')
            ->assertStatusOk()
            ->assertJsonPath('email', '[email protected]');
    }
}

use Tyloo\Atc\ApiTestCase;
use Tyloo\Atc\Http\ApiClient;

abstract class BaseApiTestCase extends ApiTestCase
{
    #[\Override]
    protected function authenticate(object $user, ApiClient $client): ApiClient
    {
        $jwt = static::getContainer()->get(JWTTokenManagerInterface::class);

        return $client->withToken($jwt->create($user));
    }
}

$shopify = $this->mockService(ShopifyService::class);
$shopify->expects(self::once())
    ->method('createCustomer')
    ->willReturn('cust_123');

$this->post('/api/customers', json: ['email' => '[email protected]'])->assertStatus(201);

$notifier = $this->partialMockService(NotifierService::class, ['send']);
$notifier->method('send')->willReturn(null);
// every other method on NotifierService keeps its real implementation.

$this->setService('app.feature_flags', new InMemoryFeatureFlags(['beta' => true]));

abstract class BaseApiTestCase extends ApiTestCase
{
    protected function defaultMocks(): array
    {
        return [
            ShopifyService::class => fn () => $this->createMock(ShopifyService::class),
        ];
    }
}

final class CreateUserTest extends ApiTestCase
{
    use Factories;
    use ResetDatabase;
    use InteractsWithDatabase;

    #[Test]
    public function admin_creates_user_persists_row(): void
    {
        $admin = UserFactory::createOne(['role' => 'admin']);

        $this->actingAs($admin)
            ->post('/api/users', json: ['email' => '[email protected]'])
            ->assertStatus(201);

        $this->assertDatabaseHas(User::class, ['email' => '[email protected]']);
        $this->assertDatabaseMissing(User::class, ['email' => '[email protected]']);
        $this->assertDatabaseCount(User::class, 2);
    }
}

use Tyloo\Atc\Trait\InteractsWithMessenger;

final class BulkImportTest extends ApiTestCase
{
    use InteractsWithMessenger;

    #[\PHPUnit\Framework\Attributes\Test]
    public function csv_upload_queues_one_message_per_row(): void
    {
        $this->post('/api/imports', files: ['csv' => $this->uploadCsv('100-rows.csv')])
            ->assertStatus(202);

        $this->assertMessagesDispatchedCount(100, ImportRow::class);
        $this->assertMessageDispatched(
            ImportRow::class,
            fn (ImportRow $row) => $row->email === '[email protected]',
        );
    }
}

$this->assertNoMessagesDispatched();                    // any class
$this->assertNoMessagesDispatched(SendEmail::class);    // class-specific

$all     = $this->dispatchedMessages();                 // list<object>
$welcomes = $this->dispatchedMessages(SendWelcomeEmail::class);

use Tyloo\Atc\Trait\InteractsWithMailer;

final class PasswordResetTest extends ApiTestCase
{
    use InteractsWithMailer;

    #[\PHPUnit\Framework\Attributes\Test]
    public function reset_request_sends_a_one_time_link(): void
    {
        $this->post('/api/password/reset', json: ['email' => '[email protected]'])
            ->assertStatusOk();

        $this->assertEmailSent();
        $this->assertEmailSentTo(
            '[email protected]',
            fn (Email $email) => str_contains((string) $email->getSubject(), 'Reset your password'),
        );
        $this->assertNoEmailsSent(); // for negative paths
    }
}

use Tyloo\Atc\Trait\InteractsWithNotifier;

final class OutageAlertTest extends ApiTestCase
{
    use InteractsWithNotifier;

    #[\PHPUnit\Framework\Attributes\Test]
    public function downstream_error_pages_the_oncall(): void
    {
        $this->mockService(StatusPageClient::class)
            ->method('latest')
            ->willThrowException(new \RuntimeException('upstream down'));

        $this->get('/api/health')->assertStatus(503);

        $this->assertNotificationSent();
        $this->assertSame(1, $this->sentNotifications()->count());
    }
}

use Symfony\Component\HttpClient\Response\MockResponse;
use Tyloo\Atc\Trait\InteractsWithHttpClient;

final class GeocodingTest extends ApiTestCase
{
    use InteractsWithHttpClient;

    #[\PHPUnit\Framework\Attributes\Test]
    public function address_lookup_calls_geocoder_with_signed_query(): void
    {
        $this->mockHttpClient([
            new MockResponse(json_encode(['lat' => 48.85, 'lng' => 2.35]), ['http_code' => 200]),
        ]);

        $this->post('/api/addresses', json: ['street' => '1 rue de Rivoli'])
            ->assertStatus(201)
            ->assertJsonPath('lat', 48.85);

        $this->assertHttpRequestSent('GET', 'https://api.example.com/geocode');
    }
}

use Tyloo\Atc\Trait\InteractsWithCache;

final class RateLimitTest extends ApiTestCase
{
    use InteractsWithCache;

    #[\PHPUnit\Framework\Attributes\Test]
    public function fourth_request_in_a_minute_is_throttled(): void
    {
        for ($i = 0; $i < 3; $i++) {
            $this->get('/api/search?q=foo')->assertStatusOk();
        }

        $this->get('/api/search?q=foo')->assertStatus(429);

        $this->clearCache(); // reset between sub-scenarios
        $this->get('/api/search?q=foo')->assertStatusOk();
    }
}

use Tyloo\Atc\Trait\InteractsWithProfiler;

final class ListUsersTest extends ApiTestCase
{
    use InteractsWithProfiler;

    #[\PHPUnit\Framework\Attributes\Test]
    public function list_endpoint_uses_a_single_query_regardless_of_user_count(): void
    {
        UserFactory::createMany(50);

        $this->withProfiling();

        $this->get('/api/users')
            ->assertStatusOk()
            ->assertJsonCount(50, 'data');

        $this->assertQueryCount(1);            // exactly one SELECT
        $this->assertQueryCountLessThan(3);    // looser bound

        $profile = $this->profile();           // raw Symfony Profile for deeper introspection
    }
}

use Tyloo\Atc\ApiTestCase;
use Tyloo\Atc\Http\ApiClient;

abstract class BaseApiTestCase extends ApiTestCase
{
    /** Default headers sent with every request. */
    #[\Override]
    protected function resolveDefaultHeaders(): array
    {
        return ['Accept' => 'application/json', 'X-Tenant' => 'acme'];
    }

    /** Where JSON Schema files live (`<project_dir>/tests/Schemas` by default). */
    #[\Override]
    protected function resolveJsonSchemaBaseDir(): string
    {
        return static::$kernel->getProjectDir() . '/tests/api-schemas';
    }

    /** Services replaced with default doubles for every test in this suite. */
    #[\Override]
    protected function defaultMocks(): array
    {
        return [
            ShopifyService::class => fn () => $this->createMock(ShopifyService::class),
        ];
    }

    /** Auth strategy: map a user to an authenticated client. */
    #[\Override]
    protected function authenticate(object $user, ApiClient $client): ApiClient
    {
        return $client->withToken($this->jwt()->create($user));
    }

    /** Pin the in-memory messenger transports instead of auto-discovering. */
    #[\Override]
    protected function resolveMessengerTransports(): array
    {
        return ['async', 'failed'];
    }

    /** Let unmatched outbound HTTP requests pass through instead of failing. */
    #[\Override]
    protected function resolveHttpClientStrict(): bool
    {
        return false;
    }

    /** Swap additional cache pools (default: just `cache.app`). */
    #[\Override]
    protected function cachePoolIds(): array
    {
        return ['cache.app', 'cache.system'];
    }
}