Integrationstests von PHP mit Docker: Fortgeschrittenes Niveau
Integrationstests sind ein kritisch wichtiger Schritt in der Entwicklung, insbesondere für komplexe PHP-Anwendungen, die mit Datenbanken, Warteschlangen, externen APIs und anderen Diensten interagieren. Docker ermöglicht es, eine isolierte Umgebung bereitzustellen, die der Produktion so nahe wie möglich kommt, und Tests unter reproduzierbaren Bedingungen durchzuführen. In diesem Artikel behandeln wir fortgeschrittene Techniken: die Organisation von Testcontainern, die Simulation externer Abhängigkeiten, parallele Ausführung und Integration in CI/CD.
1. Architektur der Testumgebung mit docker-compose
Für Integrationstests verwenden wir eine separate docker-compose.test.yml, die nur die notwendigen Dienste startet: PHP-FPM mit Testcode, eine Datenbank (z. B. PostgreSQL), Redis und optional einen Mock-Server für externe APIs.
version: '3.8'services: php-test: build: context: . dockerfile: Dockerfile.test volumes: - .:/var/www/html environment: DATABASE_URL: "pgsql://test:test@db-test:5432/testdb" REDIS_URL: "redis://redis-test:6379" EXTERNAL_API_URL: "http://mock-server:1080" depends_on: - db-test - redis-test - mock-server
db-test: image: postgres:15-alpine environment: POSTGRES_DB: testdb POSTGRES_USER: test POSTGRES_PASSWORD: test ports: - "5433:5432" # Konflikt mit der Hauptdatenbank vermeiden
redis-test: image: redis:7-alpine ports: - "6380:6379"
mock-server: image: mockserver/mockserver:latest environment: MOCKSERVER_PROPERTY_FILE: /config/mockserver.properties volumes: - ./tests/mockserver:/config ports: - "1080:1080"Beachten Sie: Wir verwenden separate Ports für die Testdienste, damit sie die lokale Entwicklung nicht stören.
2. Vorbereitung von PHPUnit und Initialisierung der Testdatenbank
Konfiguration der phpunit.xml für Integrationstests:
<phpunit bootstrap="tests/bootstrap.php"> <testsuites> <testsuite name="Integration"> <directory>tests/Integration</directory> </testsuite> </testsuites> <php> <env name="APP_ENV" value="test"/> <env name="KERNEL_CLASS" value="App\\Kernel"/> </php></phpunit>Die Datei tests/bootstrap.php ist für die Initialisierung des Datenbankschemas und das Laden von Testdaten verantwortlich:
require __DIR__ . '/../vendor/autoload.php';
// Datenbankschema erstellen$pdo = new PDO('pgsql:host=db-test;port=5432;dbname=testdb', 'test', 'test');$pdo->exec(file_get_contents(__DIR__ . '/../migrations/schema.sql'));
// Fixtures ladenrequire __DIR__ . '/Fixtures/LoadFixtures.php';Dieser Ansatz stellt sicher, dass jeder Testlauf mit einem sauberen, vorhersagbaren Zustand beginnt.
3. Testen mit externen APIs: MockServer und WireMock
Zur Simulation externer HTTP-Dienste verwenden wir MockServer (oder WireMock). Wir erstellen eine Erwartungskonfiguration in einer JSON-Datei:
// tests/mockserver/expectations/payment.json{ "httpRequest": { "method": "POST", "path": "/api/v1/charge" }, "httpResponse": { "statusCode": 200, "body": "{\\"status\\": \\"success\\", \\"transaction_id\\": \\"txn_123\\"}", "headers": { "Content-Type": "application/json" } }}Im PHP-Testcode senden wir eine Anfrage an die tatsächliche URL, die über eine Umgebungsvariable auf den Mock-Server verweist:
class PaymentIntegrationTest extends TestCase{ private PaymentService $paymentService;
protected function setUp(): void { $this->paymentService = new PaymentService( new HttpClient(['base_uri' => $_ENV['EXTERNAL_API_URL']])