Testing

Running the suite

php mitosis test delegates to the bundled PHPUnit — no bespoke test runner. The same command is also available as a Composer script:

php mitosis test
# or
composer run test

Tests live in resources/tests/, mirroring the namespace of the code they cover.

No real database required

resources/tests/bootstrap.php (wired via phpunit.xml.dist's bootstrap attribute) sets the small amount of ambient state a few middleware stubs read at construction — APP_SECRET, the APP constant — without touching .env or a real database connection:

<?php

declare(strict_types=1);

require __DIR__ . '/../../vendor/autoload.php';

putenv('APP_SECRET=test-suite-secret-do-not-use-in-production');
putenv('APP_NAME=Test App');
putenv('BASE_URL=http://127.0.0.1');

require __DIR__ . '/../../config/dir.php';

A test that touches the database opens its own in-memory SQLite connection and runs the real migrations against it — no fixtures file, no seeded test database to keep in sync:

use Monad\Clarity\Services\DB;
use Monad\Clarity\Services\Migration;
use PHPUnit\Framework\Attributes\Before;

#[Before]
public function setUpDatabase(): void
{
    DB::useConnection(new PDO('sqlite::memory:'));
    Migration::migrate(dirname(__DIR__, 3) . '/database/migrations');
}

Testing a route

Routes are tested the same way public/index.php runs them in production — Route::dispatch() against a real Request, no HTTP server involved:

use Monad\Clarity\Services\Request;
use Monad\Clarity\Services\Route;

public function testGreetingRouteReturnsTheNameFromTheUrl(): void
{
    Route::reset();
    require dirname(__DIR__, 2) . '/app/routes/web.php';

    $request = Request::fromArrays(
        server: ['REQUEST_METHOD' => 'GET', 'REQUEST_URI' => '/hello/Marshal', 'HTTP_HOST' => '127.0.0.1'],
    );
    $response = Route::dispatch($request);

    self::assertSame(200, $response->status());
    self::assertStringContainsString('Hello, Marshal!', $response->content());
}

This is the same pattern as the Quickstart route — write this test once /hello/{name} exists and it exercises the exact code path a real request would.

Next steps

  • Routing — the full Route API this pattern dispatches against.
  • Deploymentphp mitosis health, the same acceptance gate CI should run before a deploy.
  • FAQ — common questions about the test tooling, including what mitosis does and doesn't generate for you.