Pregunta

I'm developing some unit tests on a serial application in c++ using google mock framework.

The mock I've built for my serial port interface is:

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

The implementation of NotifySerialObserver in my real implementation is:

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

And the test I'm using is:

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

I need to test that when port1->NotifySerialObserver() is called serialPortManager reads from port1. Is there a way of invoke serialPortManager->HandleSerialEvent(COM1) from the mocked serial port?

EDIT This is the serialPortManager constructor

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);
    }
    }
¿Fue útil?

Solución

Firstly, you'll need to restructure your test to ensure that the SerialPortManager and MockSerialPortFactory are created in SetUp() and destroyed in TearDown(). You'll also need a member function to call HandleSerialEvent with the correct arguments on 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);
    }
};

Then your test can invoke the member function on a call to the mock serial port:

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

}

Note that I'm not sure from your code where CreateSerialPort is called inside SerialPortManager. If it's called inside the constructor for SerialPortManager, then you'll also have to move the MockSerialPort construction and destruction to SetUp() and TearDown(), respectively.

Update Here's a suggested implementation given that CreateSerialPort is called inside SerialPortManager. I've used NiceMock to get rid of the uninteresting mock function call warnings. I've also left the MockSerialPort construction inside the test body for simplicity. Essentially you have to ensure that the EXPECT_CALL for CreateSerialPort occurs before the SerialPortManager is constructed:

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

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top