web-dev-qa-db-fra.com

Fonction libre moqueuse

Je suis coincé dans un problème et n'arrive pas à trouver la solution.

J'utilise VS2005 SP1 pour compiler le code.

J'ai une fonction globale:

A* foo();

J'ai un cours simulé

class MockA : public A {
public:
    MOCK_METHOD0 (bar, bool());
    ...
};

Dans les sources, on y accède comme suit: foo()->bar(). Je ne peux pas trouver un moyen de se moquer de ce comportement. Et je ne peux pas changer les sources, donc la solution dans google mock cook book est hors de question.

Toute aide ou indication dans la bonne direction sera vivement appréciée. :)

9
Muhammad Hassan

Non, ce n'est pas possible, sans changer les sources, ni apporter votre propre version de foo() qui est liée au code exécutable.


De FAQ de GoogleMock

Mon code appelle une fonction statique/globale. Puis-je m'en moquer?

Vous pouvez le faire, mais vous devez apporter des modifications.

En général, si vous avez besoin de vous moquer d'une fonction statique, cela signifie que vos modules sont trop étroitement couplés (et moins flexibles, moins réutilisables, moins testables, etc.). Il est probablement préférable de définir une petite interface et d’appeler la fonction à travers cette interface, qui peut ensuite être facilement simulée. C'est un peu de travail au début, mais généralement rentabilisé rapidement.

Ce blog de test de Google post le dit très bien. Vérifiez-le.

Aussi à partir du Cookbook

Se moquer des fonctions gratuites

Il est possible d'utiliser Google Mock pour simuler une fonction libre (c'est-à-dire une fonction de style C ou une méthode statique). Il vous suffit de réécrire votre code pour utiliser une interface (classe abstraite).

Au lieu d'appeler directement une fonction libre (par exemple, OpenFile), introduisez une interface et une sous-classe concrète qui appelle la fonction libre:

class FileInterface {
 public:
  ...
  virtual bool Open(const char* path, const char* mode) = 0;
};

class File : public FileInterface {
 public:
  ...
  virtual bool Open(const char* path, const char* mode) {
    return OpenFile(path, mode);
  }
};

Votre code devrait parler à FileInterface pour ouvrir un fichier. Maintenant, il est facile de se moquer de la fonction.

Cela peut sembler très fastidieux, mais en pratique, vous avez souvent plusieurs fonctions connexes que vous pouvez placer dans la même interface, de sorte que la surcharge syntaxique par fonction sera beaucoup moins lourde.

Si vous êtes préoccupé par la surcharge de performances engendrée par les fonctions virtuelles et que le profilage confirme votre problème, vous pouvez le combiner avec la recette de simulation des méthodes non virtuelles.


Comme vous l'avez mentionné dans votre commentaire, vous fournissez votre propre version de foo(), vous pouvez facilement résoudre ce problème en ayant une instance globale d'une autre classe fictive:

struct IFoo {
    virtual A* foo() = 0;
    virtual ~IFoo() {}
};

struct FooMock : public IFoo {
     FooMock() {}
     virtual ~FooMock() {}
     MOCK_METHOD0(foo, A*());
};

FooMock fooMock;

// Your foo() implementation
A* foo() {
    return fooMock.foo();
}

TEST(...) {
    EXPECT_CALL(fooMock,foo())
        .Times(1)
        .WillOnceReturn(new MockA());
    // ...
}

N'oubliez pas de supprimer toutes les attentes en matière d'appels après chaque test.

14
πάντα ῥεῖ

Bien sûr, la réponse expliquant la solution selon la documentation de GTest/GMock ne pourrait pas être beaucoup plus correcte.

Mais je voudrais ajouter une approche temporaire rapide et sale. Cela devrait être applicable dans les cas où vous souhaitez tester le code C/C++ hérité aussi rapidement et de manière non invasive que possible. (Juste pour procéder aux corrections, refactoring et tests plus appropriés dès que possible après.)

Donc, pour simuler une fonction libre void foo(int) apparaissant dans un code à tester, dans le fichier source, vous apportez simplement les adaptations suivantes:

#if TESTING
#define foo(param) // to nothing, so calls to that disappear
#endif

// ... code that calls foo stays untouched and could be tested

La macro TESTING, indiquant que le code est en cours de test, ne vient pas avec GTest/GMock - vous devez l'ajouter aux cibles à tester par vous-même.

Les possibilités sont plutôt limitées, mais vous pourriez également être en mesure de construire quelque chose d'utile pour les types de retour comme A* dans l'exemple de la question.

Malheureusement, ce n’est pas une solution sans changer le code. Si cela est vraiment nécessaire, vous pouvez utiliser Google pour les "liens de liens". Mais je suppose que cela pourrait être assez compliqué en pratique. Et cela pourrait même ne pas être possible dans beaucoup/la plupart des cas?!

0
yau