Question

Je travaille actuellement sur une classe qui utilise une autre classe qui ne dispose que des fonctions statiques.

Tout fonctionnait bien jusqu'à ce que j'ai essayé de tester ma classe.

Voici un exemple simple de code du problème:

class A {
    static String getSometing() {
        return String("Something: ") + heavyCalculation().asString();
    }
}

class B {
    B() {}
    ~B() {}
    String runSomething(const String& name) {
        if(name.equals("something")) {
            return A::getSomething();
        } else {
            return "Invalid name!";
        }
    }
}

En supposant une classe fonctionne correctement (et a été testé par ses tests unitaires), je voudrais vérifier la fonction runSomething dans la classe B.

Ma première option serait de créer des simulacres pour les classes internes (dans cet exemple - classe A), mais dans ce cas, il me donnera rien à hériter d'un car il ne dispose que des fonctions statiques.

La deuxième option consiste à encapsuler les appels à la classe A dans les fonctions privées à l'intérieur B pour que je puisse contrôler leurs valeurs de retour (bien que le choix de cette option fera bien un peu plus complexe).

Ma question est la suivante: Y at-il de meilleures façons de tester les classes C ++ qui dépend de classes / fonctions statiques que mes options actuelles

Merci à l'avance,

Tal.

Était-ce utile?

La solution

Je l'ai eu du succès dans les tests unitaires dans des situations similaires par refactorisation les références aux fonctions statiques (dans mon cas, il était dépendances externes) dans de nouvelles fonctions privées et réécrites sur le talon testé, donc je peux recommander cette approche

Si les fonctions refactorisé restent privées, ils ne devraient pas un grand impact sur la complexité de la conception et ils devraient être assez faible pour ne pas avoir un impact négatif sur la lisibilité du code.

Autres conseils

Si vous n'êtes pas à l'aide d'une suite de test monolithique, puis il est facile. Je suppose que vous avez la classe A à la classe B et A.cpp en B.cpp, et les essais pour B sont B_test.cpp.

Créez un fichier appelé A_mock.cpp

class A
{
    static String getSometing() {
        return String("Expected Something");
    }
};

Ensuite, lors de la compilation de votre fichier B_test, lien juste avec A_mock.o plutôt que A.o.

g++ -Wall B_test.cpp B.cpp A_mock.cpp

Vous pourriez passer un pointeur vers la fonction au constructeur de la classe A. Ensuite, pour tester, vous pouvez passer un peu le pointeur vers une fonction simulation où vous pouvez faire ce que vous voulez.

Pourquoi la fonction statique? Je suggère de ne pas rendre statique.

Vous pouvez ensuite créer une interface pour une classe (en C ++, cela signifie une classe avec seulement les en-têtes de fonctions virtuelles pures) nommée AInterface. Classe A mettrait en œuvre (Hériter) AInterface et mettre en œuvre ces fonctions virtuelles.

Passez ensuite un pointeur vers cette interface dans le constructeur de la classe B et la stocker dans une variable membre nommée m_A. Ensuite, dans votre test, créez MockClassA qui implémente AInterface. Col MockClassA dans constructeur de classe B et régler m_A à l'entrée.

class AInterface
{
   virtual String getSomething() = 0;
}

class A : public AInterface
{
    String getSometing() {
        return String("Something: ") + heavyCalculation().asString();
    }
}

class B 
{
    B(AInterface A) :  { m_A = A; }
    ~B() {}
    String runSomething(const String& name) {
        if(name.equals("something")) {
            return m_A.getSomething();
        } else {
            return "Invalid name!";
        }
    }
    AInterface m_A;
}

Code d'essai

class MockClassA : public AInterface
{
    String getSometing() {
        return String("Whatever I want. This is a test");
    }
}   

void test ()
{
   // "MockClassA" would just be "A" in regular code
   auto instanceOfB = B(MockClassA());

   String returnValue = instanceOfB.runSomething("something");
   :
   :
}

Je dirais, « L'homme, certaines personnes prennent les tests unitaires trop loin! »

Juste tester les deux classes comme une seule unité. Classe A est codé en dur dans la classe B de toute façon.

Vous devez prendre la classe par modèle, et explicitement exporter que instanciation (B<A>) pour éviter les problèmes de l'éditeur de liens si elle n'a pas été précédemment tout en ligne telle que publiée. De cette façon, vous pouvez insérer d'autres classes aux fins de tests que vous avez besoin et est une bonne pratique de toute façon. Je suis aussi curieux de savoir pourquoi votre exemple ressemble tellement à Java -. Je devais le lire cinq fois avant de déterminer qu'il fait n'a C ++ comme indiqué

template<typename T> class BImpl {
    String runSomething(const String& name) {
        if(name.equals("something")) {
            return T::getSomething();
        } else {
            return "Invalid name!";
        }
    }
};
typedef BImpl<A> B; // Just plugs in to existing code.

Maintenant, vous pouvez remplacer une classe fantaisie A, même si vous ne pouvez pas en hériter. Enfait, ce qui est également extensible d'une autre manière -. CRTP

class A : public BImpl<A> {
    String getSomething() {
        // Now it's non-static! IT'S A MIRACLE!
    }
}

Les merveilles de modèles ne cessent jamais de me surprendre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top