在Google Mock中使用new运算符创建的Class实例进行模拟和期望

时间:2016-01-11 10:17:18

标签: googletest gmock

需要您输入以下内容: 我面临着一个关于如何为基类(StackBT)编写模拟的问题,在我想测试的派生类的构造函数(ApplicationBT)中创建了一个实例。 我的目的是为StackBT类(Mock_StackBT)编写一个模拟,然后将其链接到单元测试,以便在执行" new StackBT()"时创建模拟实例。在ApplicationBT的构造函数中。因此,使用它我可以在测试ApplicationBT类时模拟对StackBT类的期望。

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

编译以下代码片段时出现上述编译错误:

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();
}

1 个答案:

答案 0 :(得分:0)

第一个问题是您在mockPtr_StackBT中使用的是TestApplicationBT.cpp,但它是在Mock_StackBT.cpp中定义的 ApplicationBT::init。第二个问题是对registerCallbacks方法的调用调用函数 sendBTMacAddressmpoStackBT通过指针ApplicationBT,但如果你仔细观察 类StackBT的构造函数,您将看到此指针设置为类Mock_StackBT的对象 而不是registerCallbacks。这会导致链接器错误,因为您没有实现函数 <{1}}和sendBTMacAddress用于课程StackBT,您只是声明了它们。

主要的问题是你没有用模拟交换真正的实现,你的方法是 不正确。首先,不要假设您为函数registerCallbacks创建实现 和模拟类中的sendBTMacAddress,googlemock为你做了(文件Mock_StackBT.cpp完全是 不必要)。此外,您需要一个用于类StackBTMock_StackBT的通用界面,以便您可以 切换实现。这是你如何做到的:

创建界面:

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

为生产创建类:

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
    }
}

创建模拟类:

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

现在,让您的班级ApplicationBT持有IStackBT指针并使用某种形式的工厂方法 创建实际或模拟对象,具体取决于构建单元测试或部署代码的事实。那里 有几种方法,这就是我在gmock项目中的做法。为单元测试创​​建预处理器定义 表示代码是为单元测试构建的项目。例如,如果它是名为MY_UNIT_TESTS,那么在 ApplicationBT的构造函数执行以下操作:

ApplicationBT() : mpoStackBT(createStackBT())

其中createStackBT是一个定义为的函数:

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

在构建单元测试可执行文件时,这将在编译期间执行交换实现。由于您在编写更多测试时将在几个类上执行此交换,因此我建议您将工厂函数包装在某个类中,该类提供所需类型的实现(模拟或生产)。例如,我的项目有一个名为ImplementationProvider的类来执行此任务。