Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Testing Framework Laravel Package

typo3/testing-framework

The TYPO3 Testing Framework offers a complete toolset for testing TYPO3 extensions and core. It covers unit, functional, and acceptance tests, provides fixtures, a base TestCase, and Codeception helpers, and simplifies database-backed test setups.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the framework as a dev dependency alongside the core packages it needs to boot a test instance:

composer require --dev typo3/testing-framework
composer require --dev typo3/cms-core typo3/cms-install typo3/cms-frontend typo3/cms-backend

Match the framework's major version to your TYPO3 core major — the package's composer.json require block is the source of truth, and mixing majors produces confusing bootstrap failures rather than clean errors.

Look at two classes first:

  • TYPO3\TestingFramework\Core\Functional\FunctionalTestCase — boots a real TYPO3 instance, database included.
  • TYPO3\TestingFramework\Core\Unit\UnitTestCase — plain PHPUnit with TYPO3-specific helpers; no database, no bootstrap.

The first real use case is almost always "test my Extbase controller/repository against a real database." Create Tests/Functional/, add a fixture folder, and extend FunctionalTestCase:

<?php
declare(strict_types=1);

namespace Vendor\Site\Tests\Functional;

use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;

final class ArticleRepositoryTest extends FunctionalTestCase
{
    protected array $testExtensionsToLoad = ['vendor/site'];
    protected array $coreExtensionsToLoad = ['extbase', 'fluid'];

    protected function setUp(): void
    {
        parent::setUp();
        $this->importCSVDataSet(__DIR__ . '/Fixtures/pages.csv');
        $this->importCSVDataSet(__DIR__ . '/Fixtures/tx_site_domain_model_article.csv');
    }

    public function testFindByTitle(): void
    {
        $repository = $this->get(\Vendor\Site\Domain\Repository\ArticleRepository::class);
        self::assertCount(1, $repository->findByTitle('Hello'));
    }
}

Minimum PHPUnit config (place it in Build/phpunit/FunctionalTests.xml, adjust the relative bootstrap path):

<phpunit bootstrap="../../vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTestsBootstrap.php"
         colors="true" failOnWarning="true">
    <testsuites>
        <testsuite name="functional">
            <directory>../../Tests/Functional</directory>
        </testsuite>
    </testsuites>
</phpunit>

Run it with SQLite for the fastest local loop:

typo3DatabaseDriver=pdo_sqlite vendor/bin/phpunit -c Build/phpunit/FunctionalTests.xml

Implementation Patterns

Configure the instance, not the environment. The protected properties on FunctionalTestCase are the intended extension points:

protected array $pathsToLinkInTestInstance = [
    'typo3/sysext/site/Tests/Functional/Fixtures/Sites' => 'typo3conf/sites',
];
protected array $additionalFoldersToCreate = ['fileadmin/user_upload'];
protected array $configurationToUseInTestInstance = [
    'SYS' => ['features' => ['skipPageNotFoundHandling' => true]],
];

pathsToLinkInTestInstance uses source path ⇒ target path relative to the instance root, and the target's parent must exist — use $additionalFoldersToCreate for that.

Backend vs. frontend tests.

// Backend: authenticates a real be_user record
$this->setUpBackendUserFromFixture(1);

// Frontend: creates a site config + root page and includes your TypoScript
$this->setUpFrontendRootPage(1, [
    'EXT:site/Configuration/TypoScript/setup.typoscript',
]);

$response = $this->executeFrontendSubRequest(
    (new ServerRequest('https://example.org/'))->withQueryParams(['id' => 1])
);
self::assertSame(200, $response->getStatusCode());

For custom site configuration, write it into $this->instancePath . '/typo3conf/sites/' after parent::setUp() and before the first request.

Mock at the container boundary. In functional tests, replace a service rather than the class under test:

$this->getContainer()->set(
    MailerInterface::class,
    $this->createMock(MailerInterface::class)
);

Then fetch the subject via $this->get(MyService::class). This keeps the rest of the object graph real.

Fixtures are CSV-first. importCSVDataSet() and assertCSVDataSet() are the stable, readable API for seeding and asserting table state. Use explicit uid values so relations survive import, and split fixtures by concern (pages.csv, tt_content.csv, domain records). Data providers work normally — in PHPUnit 10+ they must be public static.

Unit tests stay cheap. For anything that doesn't touch the database, UnitTestCase plus constructor injection beats a functional test by an order of magnitude. Reserve functional tests for SQL, TCA, TypoScript, routing, and middleware behavior.

CI pattern. Matrix over PHP and TYPO3 core versions, one job per database driver (pdo_sqlite as the fast default, mysqli/pdo_pgsql for a single "real DB" lane). Use --log-junit for reporting and run the functional suite sequentially; parallelizing it requires per-process instance paths (see below).

Gotchas and Tips

  • Driver defaults bite. Without typo3DatabaseDriver=pdo_sqlite the framework tries MySQL with default credentials. SQLite is fast but not MySQL: no FIELD(), divergent LIKE case sensitivity, no REGEXP, weaker type coercion. Keep dialect-specific SQL behind a driver switch or test it on both.
  • $testExtensionsToLoad takes Composer package names, not EXT: keys. A typo yields a missing-extension error after a multi-second instance build. Confirm with composer show vendor/site first.
  • typo3/cms-install is mandatory for functional tests, even though it looks unrelated. Omitting it produces a cryptic install-tool/bootstrap exception rather than "missing package."
  • Instance path is the test's root. Use $this->instancePath for paths; never the legacy PATH_site globals. Leftover instances accumulate under .Build/Web/typo3temp/var/tests/ — clean them in CI to avoid disk pressure.
  • Parallel runs collide. Every process writes to the same test-instance location by default. Either run sequentially, or give each worker its own typo3DatabaseName / --process-isolation; ParaTest without this produces flaky, nonsensical failures.
  • Stale caches after TypoScript/site changes. The framework resets state per test, but compiled TypoScript and Fluid templates can persist across runs. Delete typo3temp/var/cache when a change "isn't taking effect."
  • Version coupling is real. Framework major ↔ core major ↔ PHPUnit major. getAccessibleMock() and getAccessibleMockForAbstractClass() are legacy and have been deprecated/removed in newer lines — prefer createMock() and constructor injection instead of chasing the deprecation.
  • Xdebug silently destroys throughput. Functional tests are already DB-bound; disable Xdebug and coverage for the functional suite and enable coverage only on the unit suite.
  • assertCSVDataSet() compares the whole table. If a test creates unrelated records, the assertion fails on rows you didn't intend to check. Either scope the fixture tightly or use the query builder for targeted assertions.
  • setUpFrontendRootPage() is a convenience, not a contract. It generates a minimal site config; the moment you need baseVariants, routing enhancers, or multiple languages, write the site configuration explicitly into instancePath after parent::setUp().
  • Extension points for reuse. Put shared fixture bootstrapping and container overrides in an abstract AbstractFunctionalTestCase in your extension, so individual test classes only declare data. Keep helpers protected, not public static, to avoid leaking test state between cases.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console