Tests d'intégration C++ avec Docker
Le développement moderne en C++ nécessite non seulement d'écrire du code de qualité, mais aussi de garantir son fonctionnement fiable dans des conditions réelles. Les tests d'intégration sont une étape clé permettant de vérifier l'interaction des composants du système : base de données, services réseau, système de fichiers. L'utilisation de Docker à ces fins offre un environnement isolé et reproductible, idéal pour les pipelines CI/CD. Dans cet article, nous allons voir comment configurer les tests d'intégration d'applications C++ avec Docker, et fournir des exemples pratiques.
Pourquoi Docker pour les tests d'intégration C++ ?
Les approches traditionnelles des tests d'intégration C++ rencontrent souvent des problèmes :
- Dépendance à l'environnement : les tests peuvent fonctionner sur la machine du développeur, mais échouer sur le serveur de build en raison de versions différentes des bibliothèques.
- Complexité de configuration : tester avec une base de données réelle ou une API externe nécessite une configuration manuelle.
- Exécution parallèle : plusieurs exécutions de tests peuvent entrer en conflit en raison de ressources partagées.
Docker résout ces problèmes en fournissant des conteneurs légers et isolés. Vous pouvez lancer une base de données de test, démarrer votre service C++ et exécuter les tests — le tout dans un seul fichier docker-compose. Cela garantit que l'environnement sera identique sur n'importe quelle machine.
Configuration du projet : exemple de base
Considérons un service C++ simple qui enregistre des données dans PostgreSQL. Pour les tests d'intégration, nous aurons besoin de :
- Le code C++ lui-même avec les tests (nous utilisons Google Test).
- Un
Dockerfilepour compiler et exécuter les tests. - Un fichier
docker-compose.ymlpour l'orchestration des conteneurs.
Structure du projet :
my_cpp_project/├── src/│ ├── main.cpp│ ├── database.cpp│ └── database.h├── tests/│ └── test_integration.cpp├── CMakeLists.txt├── Dockerfile└── docker-compose.yml
Dockerfile :
FROM gcc:latest AS builder
WORKDIR /appCOPY . .
RUN apt-get update && apt-get install -y cmake libpq-devRUN cmake -B build -DCMAKE_BUILD_TYPE=ReleaseRUN cmake --build build
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y libpq-devCOPY --from=builder /app/build/tests /app/testsCOPY --from=builder /app/build/my_app /app/my_app
ENTRYPOINT ["/app/tests"]docker-compose.yml :
version: '3.8'services: db: image: postgres:15 environment: POSTGRES_USER: testuser POSTGRES_PASSWORD: testpass POSTGRES_DB: testdb ports: - "5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U testuser -d testdb"] interval: 5s timeout: 5s retries: 5
test: build: . depends_on: db: condition: service_healthy environment: DB_HOST: db DB_PORT: 5432 DB_USER: testuser DB_PASSWORD: testpass DB_NAME: testdbRédaction de tests d'intégration en C++
Créons maintenant un test qui vérifie l'écriture et la lecture depuis la base de données. Nous utilisons Google Test et la bibliothèque libpqxx pour travailler avec PostgreSQL.
tests/test_integration.cpp :
#include <gtest/gtest.h>#include <pqxx/pqxx>#include <string>
class DatabaseTest : public ::testing::Test {protected: void SetUp() override { conn = new pqxx::connection( "host=" + std::string(std::getenv("DB_HOST")) + " port=" + std::string(std::getenv("DB_PORT")) + " user=" + std::string(std::getenv("DB_USER")) + " password=" + std::string(std::getenv("DB_PASSWORD")) + " dbname=" + std::string(std::getenv("DB")) + ); }
void TearDown() override { delete conn; }
pqxx::connection* conn;};
TEST_F(DatabaseTest, InsertAndSelect) { pqxx::work txn(*conn); txn.exec("CREATE TABLE IF NOT EXISTS test_table (id SERIAL PRIMARY KEY, value TEXT)"); txn.exec("INSERT INTO test_table (value) VALUES ('hello')"); pqxx::result result = txn.exec("SELECT value FROM test_table"); EXPECT_EQ(result[0][0].as<std::string>(), "hello"); txn.commit();}Exécution des tests
Pour exécuter les tests, il suffit de lancer la commande :
docker-compose up --build testDocker va construire l'image, démarrer le conteneur de base de données, attendre qu'il soit prêt (grâce au healthcheck), puis exécuter les tests dans le conteneur test. Les résultats s'afficheront dans la console.
Bonnes pratiques
- Utiliser des healthchecks : toujours attendre que les services dépendants soient prêts avant de lancer les tests.
- Nettoyer les données de test : dans
TearDown(), supprimez les tables créées ou utilisez des transactions rollback. - Isoler les tests : chaque test doit être indépendant et ne pas dépendre de l'état laissé par un autre test.
- Utiliser des variables d'environnement : pour la configuration de la base de données et d'autres paramètres, afin de ne pas coder en dur les valeurs.
- Versionner les dépendances : spécifiez des versions exactes pour les images Docker (par exemple
postgres:15) pour éviter les surprises.
Conclusion
Docker simplifie considérablement les tests d'intégration pour les applications C++. Il offre un environnement reproductible, élimine les problèmes de configuration et s'intègre parfaitement dans les pipelines CI/CD. En utilisant docker-compose, vous pouvez facilement orchestrer plusieurs services et exécuter des tests de manière fiable. Essayez cette approche dans vos projets — elle vous fera gagner du temps et des nerfs.