TYPO3
php-ci is a good fit for TYPO3 extension CI because it includes the PHP extensions
and system libraries needed by TYPO3's
typo3/testing-framework, including
pdo_sqlite for fast functional tests without a database service.
Image tag
docker pull himanshuramavat/php-ci:8.3
# Also published on the GitHub Container Registry:
docker pull ghcr.io/himanshuramavat/php-ci:8.3
Choose the PHP minor tag (:8.2, :8.3, :8.4) that matches the PHP version(s)
your extension supports.
Install the testing framework
composer require --dev typo3/testing-framework
Unit tests
TYPO3 unit tests need no database. Run them directly:
docker run --rm -v "$(pwd):/app" -w /app himanshuramavat/php-ci:8.3 \
bash -c "composer install --no-interaction && \
./vendor/bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/UnitTests.xml Tests/Unit"
Functional tests (SQLite — zero infrastructure)
The simplest functional setup uses an in-memory SQLite database, which needs no separate service container:
docker run --rm \
-v "$(pwd):/app" -w /app \
-e typo3DatabaseDriver=pdo_sqlite \
himanshuramavat/php-ci:8.3 \
bash -c "composer install --no-interaction && \
./vendor/bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTests.xml Tests/Functional"
Functional tests (MySQL service)
When you need MySQL-specific behaviour, point the suite at a database service via environment variables:
docker run --rm \
-v "$(pwd):/app" -w /app \
-e typo3DatabaseHost=mysql \
-e typo3DatabaseName=typo3_test \
-e typo3DatabaseUsername=root \
-e typo3DatabasePassword=root \
himanshuramavat/php-ci:8.3 \
bash -c "composer install --no-interaction && \
./vendor/bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTests.xml Tests/Functional"
GitHub Actions example
A complete workflow with a MySQL service container:
name: TYPO3 CI
on: [push, pull_request]
jobs:
tests:
runs-on: ubuntu-latest
container:
image: himanshuramavat/php-ci:8.3
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: typo3_test
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping" --health-interval=10s
--health-timeout=5s --health-retries=5
env:
typo3DatabaseDriver: pdo_mysql
typo3DatabaseHost: mysql
typo3DatabaseName: typo3_test
typo3DatabaseUsername: root
typo3DatabasePassword: root
steps:
- uses: actions/checkout@v4
- run: composer install --no-interaction --no-progress
- name: Unit tests
run: ./vendor/bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/UnitTests.xml Tests/Unit
- name: Functional tests
run: ./vendor/bin/phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTests.xml Tests/Functional
Suggested Composer scripts
{
"scripts": {
"test:unit": "phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/UnitTests.xml Tests/Unit",
"test:functional": "phpunit -c vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTests.xml Tests/Functional",
"ci": ["@test:unit", "@test:functional"]
}
}
Tips
- Use
-e typo3DatabaseDriver=pdo_sqlitefor the fastest feedback loop; switch to MySQL/PostgreSQL only for backend-specific assertions. - Match the PHP tag (
8.2,8.3,8.4) to the versions your extension declares incomposer.json. - See the Docker Tags reference for the full tag strategy and pinning guidance.