1
votes

Méthode statique moqueuse en c ++

Je viens de commencer à travailler sur les tests unitaires à l'aide de googleTest. J'ai une situation où j'ai une méthode statique d'une classe qui appelle à l'intérieur de l'autre classe

class MockA : public A {
  public:
    MOCK_MEHTOD2(retriveJsonData, bool(std::string, Json::Value));

Dans une autre classe, j'utilise la méthode retriveJsonData de classe A.

class B {
   public:
     bool Method1 (std::string name) {
        Json::Value sampleJsonData;
        return A::retriveJsonData(name, sampleJsonData);
 }

Moquerie de la classe A

class A {
  public:
   static bool retriveJsonData(std::string name, Json::Value& responseJsonData);
}

}

Maintenant, je dois me moquer de retriveJsonData dans le test de la méthode 2 de la classe B en utilisant EXPECT_CALL.

Aidez-moi à résoudre comment puis-je tester cette situation?


1 commentaires

Une chose que j'ai faite est de "falsifier" la définition d'une vraie fonction statique ou libre (ici A :: retrieveJsonData ) pour rediriger vers un objet simulé singleton. (Si vous avez déjà "simulé" la fonction comme un stub pour que B.o lie, change ou supprime et remplace cette définition.) Je pourrai peut-être écrire une réponse à ce sujet plus tard.


3 Réponses :


1
votes

2 commentaires

N'est-ce pas possible sans changer le code source de la classe B?


Pas de cette façon. Sinon, vous pourriez avoir un drapeau à l'intérieur de A qui lui fait exécuter un comportement simulé ou un comportement normal ... Mais cela implique un petit coût de branchement + un test de mélange et du code de production dans une certaine mesure.



1
votes

Les types simulés de Google Mock fournissent des moyens de vérifier les appels attendus pour les fonctions membres non statiques, où le polymorphisme de fonction virtuelle ou les modèles peuvent être utilisés comme "couture" pour échanger les fonctions simulées contre des fonctions réelles. Ce qui est génial si vous pouvez tout concevoir ou tout refactoriser pour utiliser l'une de ces techniques. Mais parfois, il serait fastidieux de faire fonctionner les choses de cette façon dans du code hérité désordonné ou dans du code utilisant une bibliothèque externe, etc.

Dans ce cas, une autre option consiste à définir une fonction de dépendance qui n'est pas une fonction membre non statique (donc une fonction libre ou un membre statique) pour rediriger vers un objet simulé singleton. Supposons que nous ayons une unité de traduction (B.cpp) à tester unitaire, et qu'elle appelle une fonction membre non membre ou statique ( A :: retrieveJsonData ) non définie dans cette unité de traduction. P >

Normalement, pour tester B.cpp unitaire, nous noterions ses symboles de liens requis et fournirons de fausses définitions pour ceux-ci qui les stubulent, juste pour obtenir le fichier objet Bo à lier dans le programme de test unitaire:

TEST(BTest, Method1GetsJson)
{
    Mock_A_Static a_static;
    B b;
    EXPECT_CALL(a_static, retrieveJsonData(StrEq("data_x"), _));
    b.Method1("data_x");
}

Dans ce cas, nous ne voulons pas de cette fausse définition; nous le définirons plus tard pour rediriger vers un objet fictif.

Commencez par une classe fictive spécifiquement pour les appels de fonction problématiques. S'il existe d'autres fonctions membres non statiques à tester de manière ordinaire, cette classe n'est PAS la même que ces classes. (Si cela est nécessaire pour plus d'une fonction, ces classes simulées peuvent être effectuées par fonction, par classe et / ou une pour les fonctions gratuites, par bibliothèque, une pour tout; quelle que soit la manière dont vous voulez le configurer.)

class Mock_A_Static {
public:
    Mock_A_Static() {
        EXPECT_EQ(instance, nullptr);
        instance = this;
    }
    ~Mock_A_Static() {
        EXPECT_EQ(instance, this);
        instance = nullptr;
    }

    MOCK_METHOD2(retrieveJsonData, bool(std::string, Json::Value&));

private:
    static Mock_A_Static* instance;
    friend class A;
};
Mock_A_Static* Mock_A_Static::instance = nullptr;

// The function code in B.cpp will actually be directly calling:
bool A::retrieveJsonData(std::string name, Json::Value& responseJsonData)
{
    EXPECT_NE(Mock_A_Static::instance, nullptr)
        << "Mock_A_Static function called but not set up";
    if (!Mock_A_Static::instance) return false;
    return Mock_A_Static::instance->retrieveJsonData(name, responseJsonData);
}

Ensuite, mettez simplement un objet de ce type local à un test, ou dans une classe de fixture. (Un seul à la fois, cependant!)

// Fake definition:
bool A::retrieveJsonData(std::string, Json::Value&)
{ return false; }


0 commentaires

0
votes

Vous ne pouvez pas utiliser MOCK_MEHTOD2 avec des méthodes statiques. Vous pouvez définir une méthode privée dans B qui appelle simplement retriveJsonData:

Class Test_B : public B
{
   MOCK_METHOD2( retriveJsonData, bool(std::string name, Json::Value& responseJsonData));
};

Ensuite, vous pouvez écrire une classe de test à utiliser dans votre test au lieu de B:

Class B
{
public:
   bool Method1 (std::string name) {
      Json::Value sampleJsonData;
      return retriveJsonData(name, sampleJsonData); };
private:
   bool retriveJsonData(std::string name, Json::Value& responseJsonData) {
      return A::retriveJsonData(name, responseJsonData); };
};


0 commentaires