web-dev-qa-db-fra.com

Tests unitaires de méthodes privées

Je suis en train d'écrire des tests unitaires. En particulier, je veux tester certaines méthodes privées.

Jusqu'à présent, je suis venu avec l'utilisation.

#define private public

Mais cela ne me satisfait pas car cela détruira toute encapsulation du point de vue du test unitaire.

Quelles méthodes utilisez-vous pour tester des méthodes privées?.

90
Mumbles

Si les méthodes sont suffisamment complexes pour justifier des tests isolés, reformulez-les dans leur propre classe (s) et testez-les via leur interface publique. Ensuite, utilisez-les en privé dans la classe d'origine.

56
Mike Seymour

Plutôt que le méchant #define Hack vous mentionnez dans la question, un mécanisme de nettoyage est de faire le test un ami de la classe à tester. Cela permet au code de test (et uniquement au code de test) d’accéder aux particuliers tout en les protégeant de tout le reste.

Cependant, il est préférable de tester via l'interface publique. Si votre classe X a beaucoup de code dans les fonctions membres privées, il peut être intéressant d'extraire une nouvelle classe Y utilisée par l'implémentation de la classe X. Cette nouvelle classe Y peut ensuite être testée via son interface publique, sans exposer son contenu. utiliser aux clients de la classe X.

72
Anthony Williams

Si vous utilisez Google Test, vous pouvez utiliser FRIEND_TEST pour déclarer facilement votre appareil de test en tant qu'ami de la classe à tester.

Et vous savez, si les tests des fonctions privées étaient clairement mauvais, comme le disaient certaines des réponses, cela ne serait probablement pas intégré à Google Test.

Vous pouvez en savoir plus sur le fait de bien ou de mal à tester des fonctions privées dans cette réponse .

60
jlstrecker

Faites de la classe de test l'ami de la classe d'origine. Cette déclaration d'ami sera à l'intérieur du #define UNIT_TEST drapeau.

class To_test_class {
   #ifdef UNIT_TEST
     friend test_class;
   #endif
}

Maintenant, pour votre test unitaire, vous allez compiler le code avec le drapeau -DUNIT_TEST. De cette façon, vous pourrez tester la fonction privée.

Maintenant, votre code de test unitaire ne sera pas envoyé dans l'environnement de production, comme UNIT_TEST Le drapeau sera faux. Par conséquent, le code est toujours sécurisé.

De plus, vous n’avez pas besoin de bibliothèque spéciale pour les tests unitaires.

30
Manoj R

Je sais que c’est une question plus ancienne, mais il semble que personne n’ait partagé la méthode relativement bonne que je préfère, alors voici:

Changez la méthode que vous souhaitez tester de private à protected. Pour les autres classes, la méthode sera toujours private, mais vous pouvez maintenant dériver une classe "testing" de votre classe de base qui expose la fonctionnalité privée que vous souhaitez tester.

Voici un exemple minimal:

class BASE_CLASS {
  protected:
    int your_method(int a, int b);
};

class TEST_CLASS : public BASE_CLASS {
  public:
    int your_method(int a, int b) {
      return BASE_CLASS::your_method(a, b);
    }
}

Bien sûr, vous devrez mettre à jour vos tests unitaires pour exécuter vos tests sur la classe dérivée au lieu de la classe de base, mais après cela, toute modification apportée à la classe de base sera automatiquement répercutée dans la classe "testing".

13
Miloš

Après de nombreuses heures, c’est ce que j’ai décidé d’être la meilleure solution pour ceux qui souhaitent tester leurs fonctions privées. Ceci est une combinaison de réponses par Max DeLiso et Miloš .

Si vous utilisez boost :: unit-test , il existe une solution simple et élégante.

  1. Utilisez protected au lieu de private dans vos classes

    /* MyClass.hpp */
    
    class MyClass {
    
    protected:
        int test() {
            return 1;
        }
    };
    
  2. Créez un appareil :

    /* TestMyClass.cpp */
    
    class F : public MyClass {};
    
    
    BOOST_FIXTURE_TEST_SUITE(SomeTests, F)
    
    // use any protected methods inside your tests
    BOOST_AUTO_TEST_CASE(init_test)
    {
        BOOST_CHECK_EQUAL( test(), 1 );
    }
    BOOST_AUTO_TEST_SUITE_END()
    

De cette façon, vous pouvez utiliser librement l’une des fonctions MyClass sans #define private public ou en ajoutant amis à votre classe!

6
Pari

Le hack définir est une idée horrible. Réécrire arbitrairement votre code avec le préprocesseur lorsque vous compilez n'est jamais judicieux.

Comme plusieurs personnes l'ont déjà mentionné, on peut se demander si vous devriez tester des méthodes privées. Mais cela ne couvre pas le cas où vous avez intentionnellement caché des constructeurs pour restreindre l'instantiaton à certaines portées, ou à quelques autres cas plus ésotériques.

En outre, vous ne pouvez pas créer d’espace de noms en tant qu’ami et l’amitié n’est pas héritée en C++. Par conséquent, en fonction de votre infrastructure de test unitaire, vous pourriez avoir des problèmes. Heureusement, si vous utilisez Boost.Test, il existe une solution élégante à ce problème sous la forme de Fixtures.

http://www.boost.org/doc/libs/1_52_0/libs/test/doc/html/utf/user-guide/fixture/per-test-case.html

Vous pouvez créer un ami avec le projecteur et le faire instancier toutes les instances que vous utilisez dans vos fonctions de test d'unité, en les déclarant statiques sur le projecteur et avec la portée du module. Si vous utilisez un espace de noms, ne vous inquiétez pas, vous pouvez simplement déclarer votre appareil dans l'espace de noms et vos tests en dehors de celui-ci, puis utiliser l'opérateur de résolution de la portée pour accéder aux membres statiques.

Le BOOST_FIXTURE_TEST_CASE macro prendra en charge l’instanciation et la destruction de votre appareil pour vous.

5
Max DeLiso

Je ne pense pas que les tests unitaires soient nécessaires pour les méthodes privées.

Si une méthode est privée, elle ne peut être utilisée que dans cette classe. Si vous avez testé toutes les méthodes publiques à l'aide de cette méthode privée, il n'est pas nécessaire de tester cela séparément car elle n'a été utilisée que de ces nombreuses manières.

1
aeh