2016-01-11 2 views
1

Vous avez besoin de vos commentaires concernant ce qui suit: Je suis confronté à un problème concernant la façon d'écrire un faux pour une classe de base (StackBT) dont une instance est créée dans le constructeur de la classe dérivée (ApplicationBT) que je veux tester. Mon intention est d'écrire un simulacre pour la classe StackBT (Mock_StackBT), puis de le lier au test unitaire afin que l'instance du mock soit créée en faisant "new StackBT()" dans le constructeur d'ApplicationBT. Donc, en utilisant cela, je peux mocker les attentes sur la classe StackBT tout en testant la classe ApplicationBT.Se moquer et s'attendre à une instance de classe créée en utilisant un nouvel opérateur dans Google Mock

out/linux_host/obj/TestApplicationBT.o: In function `TestApplicationBT::SetUp()': 
tst/_src/TestApplicationBT.cpp:33: undefined reference to `mockPtr_StackBT' 
out/linux_host/lib/libServer.a(ApplicationBT.o): In function `ApplicationBT::init()': 
/_src/ApplicationBT.cpp:36: undefined reference to `StackBT::registerCallbacks()' 
/_src/ApplicationBT.cpp:43: undefined reference to `StackBT::sendBTMacAddress(std::string)' 
collect2: error: ld returned 1 exit status 
make: *** [out/linux_host/bin/Test] Error 1 

Je reçois l'erreur de compilation ci-dessus lors de la compilation l'extrait de code ci-dessous:

StackBT.h: 
class StackBT 
{ 
    StackBT(){} 

    void registerCallbacks(); 
    void sendBTMacAddress(std::string str); 
} 

Mock_StackBT.h: 
#include "gtest/gtest.h" 
#include "gmock/gmock.h" 
#include <string> 
using ::testing::NiceMock; 
class Mock_StackBT; 
extern NiceMock <Mock_StackBT>* mockPtr_StackBT; 
class Mock_StackBT: public StackBT 
{ 
    Mock_StackBT(){} 
    MOCK_METHOD0(registerCallbacks, void()); 
    MOCK_METHOD1(sendBTMacAddress, void(std::string str)); 
} 

Mock_StackBT.cpp: 
#include "Mock_StackBT.h" 
NiceMock <Mock_StackBT>* mockPtr_StackBT; 
void registerCallbacks() 
{ 
    mockPtr_StackBT->registerCallbacks(); 
} 

void sendBTMacAddress(std::string str) 
{ 
    mockPtr_StackBT->sendBTMacAddress(std::string str); 
} 

ApplicationBT.h: 
class ApplicationBT 
{ 
    public: 
    ApplicationBT() : mpoStackBT(new StackBT()) 

    void init() 
    { 
     mpoStackBT->registerCallbacks(); 
     mpoStackBT->sendBTMacAddress("AB:CD:EF:GH:IJ:KL"); 
    } 

    friend class TestApplicationBT; 

    scoped_ptr<StackBT> mpoStackBT; 
} 

TestApplicationBT.h 
class TestApplicationBT : public ::testing::Test 
{ 
    protected: 
     virtual void SetUp() 
     { 
    mockPtr_StackBT = &stackBTMock; 
     ptrApplicationBT = new ApplicationBT(); 
     } 
     void TearDown() 
     { 
     delete ptrApplicationBT; 
     } 
    public: 
     TestApplicationBT() 
     { 
     } 

     ~TestApplicationBT() 
     { 
     ptrApplicationBT = NULL; 
     } 

     scoped_ptr<ApplicationBT> ptrApplicationBT; 
     StackBT* ptrStackBT; 
     NiceMock<Mock_StackBT> stackBTMock; 
}; 

TEST_F(TestApplicationBT, Init) 
{ 
    EXPECT_CALL(stackBTMock, registerCallbacks()).Times(1); 
    EXPECT_CALL(stackBTMock, sendBTMacAddress(_)).Times(1); 
    ptrApplicationBT->init(); 
} 

Répondre

0

Le premier problème est que vous utilisez mockPtr_StackBT dans TestApplicationBT.cpp, mais il est défini dans Mock_StackBT.cpp. La deuxième question est que l'appel à ApplicationBT::init méthode appelle les fonctions registerCallbacks et sendBTMacAddress par pointeur mpoStackBT, mais si vous regardez attentivement le constructeur pour la classe ApplicationBT vous voulez se que ce pointeur est réglé sur un objet de classe StackBT et non Mock_StackBT . Cela provoque une erreur de lien car vous n'avez pas implémenté les fonctions registerCallbacks et sendBTMacAddress pour la classe StackBT, vous les avez déclarées.

Le problème principal est que vous n'échangez pas votre implémentation réelle avec un simulacre, votre approche est pas correcte. Tout d'abord, vous n'êtes pas supposé créer des implémentations pour les fonctions registerCallbacks et sendBTMacAddress dans la classe fictive, googlemock fait cela pour vous (le fichier Mock_StackBT.cpp est complètement inutile). En outre, vous avez besoin d'une interface commune pour les classes StackBT et Mock_StackBT afin que vous puissiez basculer les implémentations. Voici comment faire:

Créer une interface:

class IStackBT 
{ 
public: 
    virtual IStackBT() {} 
    virtual void registerCallbacks() = 0; 
    virtual sendBTMacAddress(std::string str) = 0; 
} 

Créer une classe pour la production:

class StackBT : public IStackBT 
{ 
public: 
    void registerCallbacks() override 
    { 
     // Your code that registers callbacks 
    } 
    void sendBTMacAddress(std::string str) override 
    { 
     // Your code that sends mac address 
    } 
} 

Créer une classe Mock:

class StackBTMock : public IStackBT 
{ 
public: 
    MOCK_METHOD0(registerCallbacks, void()); 
    MOCK_METHOD1(sendBTMacAddress, void(std::string str)); 
} 

Maintenant, faites votre classe ApplicationBT maintenez un pointeur IStackBT et utilisez une forme de méthode d'usine pour créer un objet réel ou simulé, selon le fait si vous construisez un test d'unité ou un code de déploiement. Il ya plusieurs façons, voici comment je l'ai fait sur mon projet gmock. Créez un préprocesseur défini pour votre projet de test qui indique que le code a été créé pour les tests unitaires.S'il est, par exemple, du nom MY_UNIT_TESTS, alors dans constructeur ApplicationBT procédez comme suit:

ApplicationBT() : mpoStackBT(createStackBT()) 

createStackBT est une fonction définie comme:

IStackBT * createStackBT() 
{ 
#ifdef MY_UNIT_TESTS 
    return new StackBTMock; 
#else 
    return new StackBT; 
#endif 
} 

Ceci effectuera l'échange de la mise en œuvre au cours temps de compilation lorsque vous construisez votre exécutable de test unitaire. Puisque vous allez effectuer ce swap sur plusieurs classes lorsque vous écrivez plus de tests, je vous suggère d'envelopper les fonctions d'usine dans une classe qui fournit les implémentations souhaitées (maquette ou production) de votre classe. Par exemple, mon projet a une classe nommée ImplementationProvider qui effectue cette tâche.

+0

Merci beaucoup :) – user1032187

+0

@ user1032187 Vous êtes les bienvenus! Veuillez marquer la réponse comme acceptée si cela vous a été utile. –