使用google mock调用带有自定义参数的类方法

时间:2014-03-07 14:40:14

标签: unit-testing invoke googletest googlemock

我正在使用谷歌模拟框架在c ++的串行应用程序上开发一些单元测试。

我为我的串口接口构建的模拟是:

class MockSerialPort: public SerialPortInterface {
public:
MOCK_METHOD0(Open, void());
MOCK_METHOD0(IsOpen,bool());
MOCK_METHOD4(Configure,void(int,int,int,SerialParity));
MOCK_METHOD0(Close,void());
MOCK_METHOD0(Read,queue<char>());
MOCK_METHOD1(RegisterSerialObserver,void(SerialObserver*));
MOCK_METHOD0(NotifySerialObserver,void());
MOCK_METHOD0(Die, void());
virtual ~MockSerialPort() {Die(); }
};

在我的实际实现中NotifySerialObserver的实现是:

void UnixSerialPort::NotifySerialObserver(){
this->serialManager->HandleSerialEvent(this->portID);
 }

我正在使用的测试是:

TEST(SerialPortManagerTest,PortReadThrowsExceptionOnReadError){
PortID portID=COM1;

MockSerialPort* port1=new MockSerialPort();
EXPECT_CALL(*port1, Read()).Times(Exactly(1)).WillOnce(Throw(SerialPortReadErrorException()));

MockSerialPort* port2=new MockSerialPort();
MockSerialPort* port3=new MockSerialPort();

MockSerialPortFactory portFactory;
EXPECT_CALL(portFactory, CreateSerialPort(_)).Times(3).
        WillOnce(ReturnPointee(&port1)).
        WillOnce(ReturnPointee(&port2)).
        WillOnce(ReturnPointee(&port3));

SerialPortManager* serialPortManager =new SerialPortManager((SerialPortFactoryInterface*)&portFactory);

 <<<Need to add EXPECT_CALL on *port1->NotifySerialObserver() that invokes serialPortManager->HandleSerialEvent(COM1)>>>>

serialPortManager->OpenPort(portID);
EXPECT_THROW(port1->NotifySerialObserver(),SerialPortReadErrorException);

delete serialPortManager;
}

我需要测试当port1-&gt; NotifySerialObserver()被调用时,serialPortManager从port1读取。有没有办法从模拟的串口调用serialPortManager-&gt; HandleSerialEvent(COM1)?

编辑这是serialPortManager构造函数

SerialPortManager::SerialPortManager(
        SerialPortFactoryInterface* serialPortFactory,SerialParserInterface* serialParser) {
    this->serialPortFactory = serialPortFactory;
    this->serialParser=serialParser;
    for (int i = 0; i < PORT_COUNT; i++) {
        ports[i] = serialPortFactory->CreateSerialPort((PortID) i);
        cout << "Created port " << i << endl;
        ports[i]->RegisterSerialObserver(this);
    }
    }

1 个答案:

答案 0 :(得分:1)

首先,您需要重新构建测试,以确保在SerialPortManager中创建MockSerialPortFactorySetUp()并在TearDown()中销毁。您还需要一个成员函数,使用HandleSerialEvent上的正确参数调用SerialPortManager

class SerialPortManager : public Test
{
    MockSerialPortFactory* portFactory;
    SerialPortManager* serialPortManager;

protected:
    virtual void SetUp()
    {
        portFactory = new MockSerialPortFactory();
        serialPortManager = new SerialPortManager(portFactory);
    }

    virtual void TearDown()
    {
        delete serialPortManager;
        delete portFactory;
    }

    void handleCOM1SerialEvent()
    {
        serialPortManager->HandleSerialEvent(COM1);
    }
};

然后,您的测试可以在调用模拟串行端口时调用成员函数:

TEST(SerialPortManagerTest,PortReadThrowsExceptionOnReadError){
PortID portID=COM1;

MockSerialPort* port1=new MockSerialPort();
EXPECT_CALL(*port1, Read()).Times(Exactly(1)).WillOnce(Throw(SerialPortReadErrorException()));

MockSerialPort* port2=new MockSerialPort();
MockSerialPort* port3=new MockSerialPort();

EXPECT_CALL(*portFactory, CreateSerialPort(_)).Times(3).
        WillOnce(Return(port1)).
        WillOnce(Return(port2)).
        WillOnce(Return(port3));

EXPECT_CALL(*port1, NotifySerialObserver()).
        WillOnce(Invoke(this, &SerialPortManagerTest::handleCOM1SerialEvent));

serialPortManager->OpenPort(portID);

}

请注意,我不确定您的代码在CreateSerialPort内调用SerialPortManager的位置。如果在SerialPortManager的构造函数内部调用它,那么您还必须将MockSerialPort构造和销毁分别移动到SetUp()TearDown()

<强>更新 这是一个建议的实现,因为在CreateSerialPort内调用了SerialPortManager。我使用NiceMock来摆脱无趣的模拟函数调用警告。为简单起见,我还将MockSerialPort结构留在了测试体内。基本上,您必须确保在EXPECT_CALL构建之前CreateSerialPort SerialPortManager发生:

class SerialPortManager : public Test
{
    MockSerialPortFactory* portFactory;
    SerialPortManager* serialPortManager;

protected:
    virtual void SetUp()
    {
        portFactory = new NiceMock<MockSerialPortFactory>();
        serialPortManager = nullptr;  // Use NULL if not using C++11.
    }

    virtual void TearDown()
    {
        delete serialPortManager;
        delete portFactory;
    }

    void createSerialPortManager()
    {
        serialPortManager = new SerialPortManager(portFactory);
    }

    void handleCOM1SerialEvent()
    {
        serialPortManager->HandleSerialEvent(COM1);
    }
};

TEST(SerialPortManagerTest,PortReadThrowsExceptionOnReadError){
PortID portID=COM1;

MockSerialPort* port1=new MockSerialPort();
EXPECT_CALL(*port1, Read())
    .Times(Exactly(1)).WillOnce(Throw(SerialPortReadErrorException()));

MockSerialPort* port2=new MockSerialPort();
MockSerialPort* port3=new MockSerialPort();

EXPECT_CALL(*portFactory, CreateSerialPort(_)).Times(3).
        WillOnce(Return(port1)).
        WillOnce(Return(port2)).
        WillOnce(Return(port3));

createSerialPortManager();

EXPECT_CALL(*port1, NotifySerialObserver()).
        WillOnce(Invoke(this, &SerialPortManagerTest::handleCOM1SerialEvent));

serialPortManager->OpenPort(portID);

}