Est-ce que gmock peut être utilisé pour modifier des fonctions C?

Gmock étant nouveau pour moi, je veux savoir comment je peux utiliser une fonction C simple appelée dans une fonction testée pour le test unitaire.

Exemple:

int func(int a) { boolean find; // Some code find = func_1(); return find; } 

J’ai cherché à propos de gmock et, à ma connaissance, gmock ne fournit pas de fonctionnalités permettant de remplacer des fonctions C simples. Par conséquent, je souhaite demander à gmock de fournir des fonctionnalités permettant de func_1 ou de func_1 ?

Sinon, comment puis-je func_1 manuellement func_1 dans mon code de test sans changer le code source? J’utilise Google Test Framework pour les tests unitaires.

Merci.

Je me suis retrouvé dans la même situation ces derniers temps. Je devais écrire des tests unitaires pour les bibliothèques écrites en C, qui avaient à leur tour des dépendances par rapport à d’autres bibliothèques également écrites en C. Je voulais donc me moquer de tous les appels de fonction des dépendances à l’aide de gmock . Permettez-moi d’expliquer mon approche par un exemple.

Supposons que le code à tester (bibliothèque A) appelle une fonction d’une autre bibliothèque, lib_x_function() :

 lib_a_function() { ... retval = lib_x_function(); ... } 

Donc, je veux me moquer de la bibliothèque X. Par conséquent, j’écris une classe d’interface et une classe de faux dans un fichier lib_x_mock.h :

 class LibXInterface { public: virtual ~LibXInterface() {} virtual int lib_x_function() = 0; } class LibXMock : public LibXInterface { public: virtual ~LibXMock() {} MOCK_METHOD0(lib_x_function, int()); } 

De plus, je crée un fichier source (par exemple, lib_x_mock.cc ), qui définit un stub pour la fonction C réelle. Cela appellera la méthode fictive. Notez la référence extern à l’object fictif.

 #include lib_x.h #include lib_x_mock.h extern LibXMock LibXMockObj; /* This is just a declaration! The actual mock obj must be defined globally in your test file. */ int lib_x_function() { return LibXMockObj.lib_x_function(); } 

Maintenant, dans le fichier de test, qui teste la bibliothèque A, je dois définir l’object lib_x_mock.cc globalement , de sorte qu’il soit accessible dans vos tests et à partir de lib_x_mock.cc . C’est lib_a_tests.cc:

 #include lib_x_mock.h LibXMock LibXMockObj; /* This is now the actual definition of the mock obj */ ... TEST_F(foo, bar) { EXPECT_CALL(LibXMockObj, lib_x_function()); ... } 

Cette approche fonctionne parfaitement pour moi, et j’ai des dizaines de tests et plusieurs bibliothèques moquées. Cependant, j’ai quelques doutes sur la possibilité de créer un object fictif global. Je l’ai posé dans une question distincte et j’attends toujours des réponses. En plus de cela, je suis content de la solution.


EDIT: Le problème de l’object global peut être facilement résolu en créant l’object, par exemple dans le constructeur du dispositif de test, et en stockant simplement un pointeur sur cet object dans une variable globale.

Cependant, notez également ma réponse alternative à cette question, que je viens de poster.

Je cherchais déjà depuis longtemps une solution pour simuler des fonctions c héritées avec googleMock sans modifier le code existant. Ces derniers jours, j’ai trouvé l’article suivant très intéressant: https://www.codeproject.com/articles/1040972/using-googletest -et-googlemock-frameworks-pour-emb

Aujourd’hui, j’ai écrit mon premier test unitaire pour les fonctions c à l’aide de gmock et ai pris comme exemple deux fonctions de la bibliothèque bcm2835.c ( http://www.airspayce.com/mikem/bcm2835/ ) pour la programmation Pi framboise: Voici ma solution. : J’utilise le gcc 4.8.3. sous Eclipse et Windows. Soyez conscient de définir l’option du compilateur -std = gnu ++ 11.

Voici mes fonctions à tester

 int inits(void); void pinMode(uint8_t pin, uint8_t mode); int inits(){ return bcm2835_init(); } void pinMode(uint8_t pin, uint8_t mode){ bcm2835_gpio_fsel(pin, mode); } 

Inclut et définit les tests unitaires avec googleTest / googleMock

 // MOCKING C-Functions with GMOCK :) #include  #include "gtest/gtest.h" #include "gmock/gmock.h" using namespace ::testing; using ::testing::Return; 

Mock BCM2835Lib fonctions

 class BCM2835Lib_MOCK{ public: virtual ~BCM2835Lib_MOCK(){} // mock methods MOCK_METHOD0(bcm2835_init,int()); MOCK_METHOD2(bcm2835_gpio_fsel,void(uint8_t,uint8_t)); }; 

Créer un TestFixture

 class TestFixture: public ::testing::Test{ public: TestFixture(){ _bcm2835libMock.reset(new ::testing::NiceMock()); } ~TestFixture(){ _bcm2835libMock.reset(); } virtual void SetUp(){} virtual void TearDown(){} // pointer for accessing mocked library static std::unique_ptr _bcm2835libMock; }; 

Instancier les fonctions de bibliothèque moquées

 // instantiate mocked lib std::unique_ptr TestFixture::_bcm2835libMock; 

Faux fonctions lib pour connecter Mocks avec les fonctions c

 // fake lib functions int bcm2835_init(){return TestFixture::_bcm2835libMock->bcm2835_init();} void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode){TestFixture::_bcm2835libMock->bcm2835_gpio_fsel(pin,mode);} 

Créer une classe de tests unitaires pour BCM2835 à partir de TestFixture

 // create unit testing class for BCM2835 from TestFixture class BCM2835LibUnitTest : public TestFixture{ public: BCM2835LibUnitTest(){ // here you can put some initializations } }; 

Écrire les tests en utilisant googleTest et googleMock

 TEST_F(BCM2835LibUnitTest,inits){ EXPECT_CALL(*_bcm2835libMock,bcm2835_init()).Times(1).WillOnce(Return(1)); EXPECT_EQ(1,inits()) << "init must return 1"; } TEST_F(BCM2835LibUnitTest,pinModeTest){ EXPECT_CALL(*_bcm2835libMock,bcm2835_gpio_fsel( (uint8_t)RPI_V2_GPIO_P1_18 ,(uint8_t)BCM2835_GPIO_FSEL_OUTP ) ) .Times(1) ; pinMode((uint8_t)RPI_V2_GPIO_P1_18,(uint8_t)BCM2835_GPIO_FSEL_OUTP); } 

Résultats 🙂

 [----------] 2 tests from BCM2835LibUnitTest [ RUN ] BCM2835LibUnitTest.inits [ OK ] BCM2835LibUnitTest.inits (0 ms) [ RUN ] BCM2835LibUnitTest.pinModeTest [ OK ] BCM2835LibUnitTest.pinModeTest (0 ms) [----------] 2 tests from BCM2835LibUnitTest (0 ms total) 

J'espère que ça va aider 🙂 - pour moi, c'est une solution qui fonctionne vraiment.

Ceci est une autre réponse de ma part à cette question. Au cours des deux années écastings depuis la première réponse, j’ai compris que GMock était tout simplement le mauvais cadre pour se moquer des fonctions C. Dans les situations où vous devez vous moquer de nombreuses fonctions, ma réponse précédemment affichée est trop lourde. La raison en est que GMock utilise Object Seams pour remplacer le code de production par du code factice. Cela repose sur des classes polymorphes, qui n’existent pas en C.

Au lieu de cela, pour simuler des fonctions C, vous devez utiliser des coutures de lien , qui remplacent le code de production par le code simulé au moment de la liaison. Plusieurs frameworks existent à cet effet, mais mon préféré est le Fake Function Framework ( FFF ). Regardez, c’est beaucoup plus simple que GMock. Cela fonctionne également parfaitement dans les applications C ++.

Pour les intéressés, voici un bon article de Michael Feathers sur les différents types de couture.

J’ai eu un cas similaire dans un projet que j’étais en test unitaire. Ma solution consistait à créer deux fichiers Make, un pour la production et un pour les tests.

Si la fonction func_1 () est définie dans l’en-tête ah et implémentée dans a.cpp, vous pouvez append un nouveau fichier source a_testing.cpp, qui implémentera toutes les fonctions de ah en tant que stub. Pour unittesting, comstackz simplement et liez avec a_testing.cpp au lieu de a.cpp et le code testé appellera votre stub.

Dans a_testing.cpp, vous pouvez ensuite transférer l’appel vers un object gmock qui définira les attentes et les actions comme d’habitude en fonction de l’état et des parameters.

Je sais que ce n’est pas parfait, mais cela fonctionne et résout le problème sans changer le code de production ou les interfaces.

Dans chaque UT, nous essayons de vérifier un comportement spécifique.

Vous devriez simuler quelque chose quand c’est très difficile / impossible (nous devons isoler notre unité ) / passer beaucoup de temps (temps courant ..) pour simuler un comportement spécifique.

Utiliser une fonction ‘C’ de manière explicite signifie que la fonction est en dehors de votre unité (par conséquent, vous ne devriez pas vous en moquer ..). Dans cette réponse, j’explique l’initiative de tester la méthode telle quelle (dans l’édition ..). À mon avis, vous devez appeler func avec les parameters qui func_1 à func_1 de simuler le comportement que vous souhaitez vérifier.

GMock est basé sur une compilation fausse (macros), vous ne pouvez donc pas faire une chose pareille. Pour simuler des méthodes ‘C’, vous devez utiliser différents outils tels que Typemock Isolator ++ .

Si vous ne souhaitez pas utiliser Isolator++ , vous devez alors refactoriser votre méthode. Remplacez func par func(int a, ) , puis utilisez le pointeur au lieu de func_1 .

Mon tableau dans cette réponse pourrait aider à décider de la manière de traiter votre cas.