Tests d'intégration PHP avec Docker : niveau avancé
Les tests d'intégration sont une étape critique du développement, en particulier pour les applications PHP complexes interagissant avec des bases de données, des files d'attente, des API externes et d'autres services. Docker permet de créer un environnement isolé, aussi proche que possible de la production, et d'exécuter les tests dans des conditions reproductibles. Dans cet article, nous aborderons des techniques avancées : l'organisation des conteneurs de test, la simulation des dépendances externes, l'exécution parallèle et l'intégration avec CI/CD.
1. Architecture de l'environnement de test avec docker-compose
Pour les tests d'intégration, nous utilisons un fichier docker-compose.test.yml séparé, qui démarre uniquement les services nécessaires : PHP-FPM avec le code de test, une base de données (par exemple, PostgreSQL), Redis et, optionnellement, un serveur mock pour les API externes.
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" # Évite les conflits avec la base de données principale
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"Remarque : nous utilisons des ports séparés pour les services de test afin qu'ils n'interfèrent pas avec le développement local.
2. Préparation de PHPUnit et initialisation de la base de données de test
Configuration du fichier phpunit.xml pour les tests d'intégration :
<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>Le fichier tests/bootstrap.php est responsable de l'initialisation du schéma de la base de données et du chargement des données de test :
require __DIR__ . '/../vendor/autoload.php';
// Création du schéma de la base de données$pdo = new PDO('pgsql:host=db-test;port=5432;dbname=testdb', 'test', 'test');$pdo->exec(file_get_contents(__DIR__ . '/../migrations/schema.sql'));
// Chargement des fixturesrequire __DIR__ . '/Fixtures/LoadFixtures.php';Cette approche garantit que chaque exécution de test commence dans un état propre et prévisible.
3. Test avec des API externes : MockServer et WireMock
Pour simuler des services HTTP externes, nous utilisons MockServer (ou WireMock). Créons une configuration d'attentes dans un fichier JSON :
// 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" } }}Dans le code PHP du test, nous envoyons une requête à l'URL réelle, qui pointe vers le mock-server via une variable d'environnement :
class PaymentIntegrationTest extends TestCase{ private PaymentService $paymentService;
protected function setUp(): void { $this->paymentService = new PaymentService( new HttpClient(['base_uri' => $_ENV['EXTERNAL_API_URL']])