Tests en C++ : unitaires, d'intégration, e2e — niveau avancé

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Tests avancés en C++ : des tests unitaires au end-to-end

Dans le développement C++ moderne, la qualité du code ne se mesure pas seulement à ses performances, mais aussi à sa fiabilité. Les tests avancés vont bien au-delà de simples vérifications — c'est une approche architecturale qui inclut les tests unitaires, les tests d'intégration et les tests end-to-end (e2e). Dans cet article, nous verrons comment construire correctement la pyramide de tests pour des projets C++, en utilisant Google Test, Google Mock et vos propres frameworks.



1. Tests unitaires : isolation et mocks

Les tests unitaires vérifient des modules individuels (fonctions, classes) de manière isolée. Au niveau avancé, la tâche clé est d'apprendre à mock-er correctement les dépendances. Considérons un exemple utilisant Google Mock.



Supposons que nous ayons une classe DatabaseConnector qui dépend d'une API externe. Nous voulons tester la logique de traitement des données sans accéder à la base de données réelle.



#include <gmock/gmock.h>#include <gtest/gtest.h>

class DatabaseInterface {public: virtual ~DatabaseInterface() = default; virtual std::string fetchData(int id) = 0;};

class MockDatabase : public DatabaseInterface {public: MOCK_METHOD(std::string, fetchData, (int id), (override));};

class DataProcessor { DatabaseInterface& db;public: explicit DataProcessor(DatabaseInterface& db) : db(db) {} std::string process(int id) { auto raw = db.fetchData(id); if (raw.empty()) return "EMPTY"; return "PROCESSED: " + raw; }};

TEST(DataProcessorTest, ProcessWithValidData) { MockDatabase mockDb; EXPECT_CALL(mockDb, fetchData(42)) .WillOnce(testing::Return("Hello")); DataProcessor processor(mockDb); EXPECT_EQ(processor.process(42), "PROCESSED: Hello");}


L'utilisation de MOCK_METHOD permet de contrôler précisément le comportement des dépendances. Il est important de se souvenir des mocks stricts (via NiceMock ou StrictMock) pour détecter les appels inattendus.



2. Tests d'intégration : tester les interactions

Les tests d'intégration vérifient comment les modules fonctionnent ensemble. En C++, cela inclut souvent le test du travail avec le système de fichiers, les protocoles réseau ou les bases de données. L'approche avancée consiste à utiliser des fixtures de test et des tests paramétrés.



Exemple : testons une classe FileManager qui lit et écrit dans des fichiers. Utilisons des répertoires temporaires.



class FileManagerTest : public ::testing::Test {protected:    std::filesystem::path tempDir;    void SetUp() override {        tempDir = std::filesystem::temp_directory_path() / "test_files";        std::filesystem::create_directories(tempDir);    }    void TearDown() override {        std::filesystem::remove_all(tempDir);    }};

TEST_F(FileManagerTest, WriteAndReadFile) { FileManager fm(tempDir.string()); fm.write("test.txt", "data"); auto content = fm.read("test.txt"); EXPECT_EQ(content, "data");}


Pour les tests paramétrés, utilisons TEST_P avec INSTANTIATE_TEST_SUITE_P. Cela permet d'exécuter le même test avec différentes données d'entrée.



class MathTest : public ::testing::TestWithParam<std::tuple<int, int, int>> {};TEST_P(MathTest, Add) {    auto [a, b, expected] = GetParam();    EXPECT_EQ(add(a, b), expected);}INSTANTIATE_TEST_SUITE_P(AddTests, MathTest,    ::testing::Values(        std::make_tuple(1, 1, 2),        std::make_tuple(-1, 1, 0),        std::make_tuple(0, 0, 0)    ));


3. Tests End-to-End : vérification du cycle complet

Les tests e2e simulent le comportement de l'utilisateur final. Pour les applications C++, cela peut signifier lancer le binaire complet, vérifier sa sortie ou interagir via une API. Niveau avancé

Blogs

Book Recommendations