Linux Embedded

Le blog des technologies libres et embarquées

Introduction à Google C++ Testing Framework

Il existe de nombreux frameworks de tests unitaires pour les programmes C et C++. Google C++ Testing Framework en est un particulièrement simple et efficace.

Google C++ Testing Framework plus généralement appelé Google Test est une bibliothèque de tests unitaires pour le langage C++ basé sur l'architecture xUnit. Cette bibliothèque permet de faire des tests unitaires sur du code source C ou C++ avec un minimum de modifications dans les sources.

Première utilisation de Google Test

Pour utiliser Google Test, il faut le compiler en une bibliothèque qui sera liée avec le programme de test.

Un test se présente comme ceci:

TEST(test_case_name, test_name)
{
    ASSERT_EQ(expected, actual);
    EXPECT_LT(val1, val2);
    ...
}

Voici quelques affirmations que l'on peut tester:

Fatal assertion Nonfatal assertion vérifie
ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition est vrai
ASSERT_EQ(expected, actual); EXPECT_EQ(expected, actual); expected == actual
ASSERT_STREQ(expected_str, actual_str); EXPECT_STREQ(expected_str, actual_str); Les 2 chaines C ont le même contenu

Ces affirmations permettent de vérifier les valeurs obtenues dans une fonction ou une méthode.
Un programme de test peut contenir plusieurs test cases qui eux-mêmes contiennent un ou plusieurs tests.
Les test cases permettent de structurer les tests.

Quand plusieurs tests dans un test case ont besoin de partager des objets ou des fonctions, on peut utiliser une classe test fixture.

Les tests fixtures

Les tests fixtures permettent d'utiliser la même configuration pour plusieurs tests.
Pour cela on défini une classe qui contiendra les éléments nécessaires aux tests.

Par exemple:

class QueueTest : public ::testing::Test
{
  protected:
    virtual void SetUp()
    {
        q1_.Enqueue(1);
        q2_.Enqueue(2);
        q2_.Enqueue(3);
    }
    // virtual void TearDown() {}
    Queue q0_;
    Queue q1_;
    Queue q2_;
};

On peut définir un constructeur et un destructeur.
La fonction SetUp() permet de préparer les objets pour chaque test.
La fonction TearDown() permet de relâcher les ressources éventuellement allouées dans la fonction SetUp().
Dans le cadre de l'utilisation d'un test fixture, on va utiliser TEST_F() à la place de TEST() pour pouvoir accéder aux objets qu'on a construit précédemment.
Par exemple:

TEST_F(QueueTest, IsEmptyInitially) 
{
    EXPECT_EQ(0, q0_.size());
}

TEST_F(QueueTest, DequeueWorks) 
{
    int* n = q0_.Dequeue();
    EXPECT_EQ(NULL, n);
    n = q1_.Dequeue();
    ASSERT_TRUE(n != NULL);
    EXPECT_EQ(1, *n);
    EXPECT_EQ(0, q1_.size());
    delete n;
    n = q2_.Dequeue();
    ASSERT_TRUE(n != NULL);
    EXPECT_EQ(2, *n);
    EXPECT_EQ(1, q2_.size());
    delete n;
}

Exécuter les tests

Enfin, pour exécuter les tests, il suffit d'initialiser googletest avec ::testing::InitGoogleTest(&argc, argv). Puis pour lancer les tests d'utiliser RUN_ALL_TESTS().

Voici un exemple complet:

#include "this/package/foo.h"
#include "gtest/gtest.h"

namespace 
{
    // The fixture for testing class Foo.
    class FooTest : public ::testing::Test 
    {
      protected:
        // You can remove any or all of the following functions if its body
        // is empty.
        FooTest() 
        {
            // You can do set-up work for each test here.
        }
        virtual ~FooTest() 
        {
           // You can do clean-up work that doesn't throw exceptions here.
        }

        // If the constructor and destructor are not enough for setting up
        // and cleaning up each test, you can define the following methods:
    
        virtual void SetUp() 
        {
           // Code here will be called immediately after the constructor (right
           // before each test).
        }

        virtual void TearDown() 
        {
          // Code here will be called immediately after each test (right
          // before the destructor).
        }
        // Objects declared here can be used by all tests in the test case for Foo.
    };

    // Tests that the Foo::Bar() method does Abc.
    TEST_F(FooTest, MethodBarDoesAbc) 
    {
        const string input_filepath = "this/package/testdata/myinputfile.dat";
        const string output_filepath = "this/package/testdata/myoutputfile.dat";
        Foo f;
        EXPECT_EQ(0, f.Bar(input_filepath, output_filepath));
    }

    // Tests that Foo does Xyz.
    TEST_F(FooTest, DoesXyz) 
    {
       // Exercises the Xyz feature of Foo.
    }
}  // namespace

int main(int argc, char **argv) 
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

Générer un rapport XML Google Test

L'un des atouts de Google Test est de permettre de générer un rapport XML.

Pour pouvoir générer un rapport XML, il faut mettre la variable d'environnement GTEST_OUTPUT à la valeur xml:\chemin\vers\Rapport_XML.xml.

Bibliographie

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.