Running functional tests 

Functional tests execute test cases within a fully initialized TYPO3 instance. Unlike unit tests, functional tests interact with the TYPO3 framework, service container, and an active database connection.

Before running functional tests, ensure that the TYPO3 testing framework ( typo3/testing-framework ) and PHPUnit ( phpunit/phpunit ) are installed as Composer development dependencies. For version compatibility between TYPO3, PHP, and the testing framework, see Install PHPUnit and the TYPO3 testing framework.

Quick setup with extension kickstarter 

If you are developing a TYPO3 extension, the fastest way to set up the test environment is using the Extension Kickstarter ( friendsoftypo3/kickstarter ):

composer require --dev friendsoftypo3/kickstarter
vendor/bin/typo3 make:testenv [extension_key]
Copied!

The command generates:

  • Build/phpunit/FunctionalTests.xml and Build/phpunit/FunctionalTestsBootstrap.php
  • Build/phpunit/UnitTests.xml and Build/phpunit/UnitTestsBootstrap.php
  • Build/Scripts/runTests.sh (the containerized test runner)
  • Standard configuration files for coding guidelines and static analysis (such as .php-cs-fixer.dist.php and phpstan.neon)
  • Enriches composer.json with the necessary require-dev and autoload-dev definitions

For more information, see Testing extensions.

Provide configuration files for functional tests 

If you set up testing manually or need to customize an existing configuration, the TYPO3 testing framework provides template files:

Copy these files into your project under Build/phpunit/.

Open FunctionalTests.xml and adjust the path in the <testsuite> definition to point to your functional test directory. Because the configuration file is located two directory levels deep in Build/phpunit/, use ../../ to navigate back to the root directory. By convention, functional tests reside in Tests/Functional/:

FunctionalTests.xml for extension testing
<testsuites>
    <testsuite name="Functional tests">
-        <directory>../../../../../../typo3/sysext/*/Tests/Functional/</directory>
+        <directory>../../Tests/Functional/</directory>
    </testsuite>
</testsuites>
Copied!

For testing within a full project with local extensions in packages/:

FunctionalTests.xml for project testing
<testsuites>
    <testsuite name="Functional tests">
-        <directory>../../../../../../typo3/sysext/*/Tests/Functional/</directory>
+        <directory>../../Tests/Functional/</directory>
+        <directory>../../packages/*/Tests/Functional/</directory>
    </testsuite>
</testsuites>
Copied!

The bootstrap file FunctionalTestsBootstrap.php instantiates \TYPO3\TestingFramework\Core\Testbase , resolves paths, and ensures the temporary directories typo3temp/var/tests and typo3temp/var/transient exist before executing test suites.

Run functional tests with runTests.sh 

The recommended and standardized approach for running tests across TYPO3 extensions is Build/Scripts/runTests.sh. It starts dedicated Docker containers with all required dependencies and manages database containers automatically.

When using runTests.sh, you do not need to configure database credentials or set environment variables manually. The script takes care of starting the database service (SQLite, MariaDB, or PostgreSQL) and injecting all necessary configuration variables into the test environment.

Run all functional tests using the default database (SQLite):

Build/Scripts/runTests.sh -s functional
Copied!

Run tests against a specific database system:

Build/Scripts/runTests.sh -s functional -d mariadb
Build/Scripts/runTests.sh -s functional -d postgres
Copied!

Run tests with a specific PHP version:

Build/Scripts/runTests.sh -s functional -p 8.4
Copied!

Run a single test file:

Build/Scripts/runTests.sh -s functional -- \
    Tests/Functional/Domain/Repository/MyRepositoryTest.php
Copied!

For more details on runTests.sh options and workflows, see Test runners.

Run functional tests on the host system or with DDEV 

If you choose not to use runTests.sh and execute PHPUnit directly on your host system or inside DDEV, you must provide the database connection details yourself via environment variables.

Functional tests create the database schema based on the TCA configuration and complementary ext_tables.sql definitions of all loaded extensions, and truncate database tables between tests. Without runTests.sh managing the environment, the test bootstrap requires the following environment variables:

typo3DatabaseDriver

Specifies the database driver:

  • pdo_sqlite: Uses an SQLite file database. This is the simplest driver for local execution because it requires no database server setup or credentials. SQLite creates database files on the fly in typo3temp/var/tests/functional-sqlite-dbs/.
  • mysqli: Connects to a MySQL or MariaDB database server.
  • pdo_pgsql: Connects to a PostgreSQL database server.

If using mysqli or pdo_pgsql, the following additional connection variables must be supplied:

  • typo3DatabaseHost (e.g. 127.0.0.1 or db)
  • typo3DatabasePort (e.g. 3306)
  • typo3DatabaseUsername
  • typo3DatabasePassword
  • typo3DatabaseName

These variables can either be passed inline when executing PHPUnit, or defined in the <php> section of Build/phpunit/FunctionalTests.xml:

Build/phpunit/FunctionalTests.xml (excerpt)
<php>
    <ini name="display_errors" value="1"/>
    <env name="TYPO3_CONTEXT" value="Testing"/>
    <env name="typo3DatabaseDriver" value="pdo_sqlite"/>
</php>
Copied!

Running with SQLite on DDEV:

ddev exec typo3DatabaseDriver=pdo_sqlite \
    php vendor/bin/phpunit -c Build/phpunit/FunctionalTests.xml
Copied!

Running with MariaDB or MySQL on DDEV:

ddev exec \
    typo3DatabaseDriver=mysqli \
    typo3DatabaseHost=db \
    typo3DatabasePort=3306 \
    typo3DatabaseUsername=db \
    typo3DatabasePassword=db \
    typo3DatabaseName=db_test \
    php vendor/bin/phpunit -c Build/phpunit/FunctionalTests.xml
Copied!

To run a single test method or test case, use the --filter option:

ddev exec typo3DatabaseDriver=pdo_sqlite \
    php vendor/bin/phpunit -c Build/phpunit/FunctionalTests.xml \
    --filter "MyFunctionalTest"
Copied!