Google Mock-如何使用EXPECT_CALL返回不同的值以退出循环

时间:2019-05-01 20:08:33

标签: c++ unit-testing googletest googlemock

使用Google模拟,如何指定EXPECT_CALL的返回值是N次,然后是另一个值N + 1?

我可以通过测试的唯一方法是手动指定每个迭代,例如

EXPECT_CALL(mock, Read(address)).Times(5)
.WillOnce(Return(0))
.WillOnce(Return(0))
.WillOnce(Return(0))
.WillOnce(Return(0))
.WillOnce(Return(1));

测试说明

被测代码使用状态字来确定是否应退出读取数据的循环。 EXPECT_CALL应该设置一个预期,以使模拟方法Read()返回N次为1,并且在第N个周期返回0以指示没有更多数据。

不幸的是,所讨论的代码在单独的机器上,但这是一个典型示例。

const unsigned int statusAddress = 0;
const unsigned int dataAddress   = 1;
const unsigned int maxData       = 8;

unsigned int dataBuffer[maxData] = {0};
int readIndex = 0;

// Check if data is available (read returns 1). 
unsigned int dataIsAvailable = Read(statusAddress);

// Keep reading data until no more is available or the buffer is full.
while ((dataIsAvailable == 1) && (readIndex < maxData))
{
    // Read data word.
    dataBuffer[readIndex++] = Read(dataAddress);

    // Read status to determine if more data is available.
    dataIsAvailable = Read(statusAddress);
}

Read方法被模拟。

如果我按顺序添加期望,则使用后者EXPECT_CALL(我假设WillOnce在Google代码中会覆盖WillRepeatedly)。显然我误解了如何订购多个EXPECT_CALL。

EXPECT_CALL(mock, Read(address)).Times(4).WillRepeatedly(Return(1));
EXPECT_CALL(mock, Read(address)).Times(1).WillOnce(Return(0));
Expected: to be called 4 times
 Actual: never called - unsatisfied and active

因为没有方法...

WillN(Return(1), 4)

...我认为,对于更复杂和/或更长时间的数据序列,构造EXPECT_CALL的方法不太固定?

2 个答案:

答案 0 :(得分:0)

有一个简单的解决方案可以解决您的问题。在您的期望之前创建一个InSequence实例。这将确保以相同的顺序调用书面期望。

InSequence s;
EXPECT_CALL(mock, Read(address)).Times(4).WillRepeatedly(Return(1));
EXPECT_CALL(mock, Read(address)).Times(1).WillOnce(Return(0));

其他信息:click

答案 1 :(得分:-1)

您可能想研究这种测试类型的Delegating Calls to Fake模式。

我认为,如果我需要实施一套处理读取各种数据流的测试,我可能会编写一个混合的Mock / Fake类,该类允许我控制要读取的实际流。例如:

// Example reader class to be tested
class Reader
{
public:
    static const unsigned int statusAddress = 0;
    static const unsigned int dataAddress   = 1;
    static const unsigned int maxData       = 8;

    // Returns data sequence that was read
    vector<unsigned int> ReadFromDevice()
    {
        // Stream-reading code from your example goes here
    }

    virtual unsigned int Read(unsigned int address)
    {
        // Read from address code here
    }
};

// Mock reader class with some faking ability
class MockReader : public Reader
{
public:
    // Set up normal mock definition
    MOCK_METHOD1(Read, unsigned int(unsigned int address));

    // Optionally enable use of delegation to fake method
    void EnableFakeReader()
    {
        ON_CALL(*this, Read(_))
            .WillByDefault(Invoke(this, &MockReader::FakeRead));
    }

    // Set up a fake data sequence to be returned by Read()
    void SetFakeData(const vector<unsigned int> &data)
    {
        m_fakeData = data;
        m_fakeDataIndex = 0;
        EnableFakeReader();
    }

    // Read from fake data sequence
    unsigned int FakeRead(unsigned int address)
    {
        if (address == statusAddress)
            return m_fakeDataIndex < m_fakeData.size() ? 1 : 0;
        if (address == dataAddress)
            if (m_fakeDataIndex < m_fakeData.size())
                return m_fakeData[m_fakeDataIndex++];
        return 0;
    }

    vector<unsigned int> m_fakeData;
    size_t m_fakeDataIndex = 0;
};

TEST(ReaderTests, Test1)
{
    // Set up a fake data sequence to be read
    vector<unsigned int> testData ={ 1,2,3,4,5,6,7,8 };
    MockReader mock;
    mock.SetFakeData(testData);

    // Set any desired expectations about mocked functions
    EXPECT_CALL(mock, Read(Reader::statusAddress)).Times(9);
    EXPECT_CALL(mock, Read(Reader::dataAddress)).Times(8);

    // Data read should be the same as the test data
    EXPECT_EQ(testData, mock.ReadFromDevice());
}

请注意,此示例未遵循上面链接的Google Mock食谱模式。完整的食谱模式将使您创建一个FakeReader类和一个MockReaderMockReader将拥有并委托给FakeReader类的私有实例。

您还可以考虑将假货放入灯具类。