c++ - 使用 GoogleMock 模拟由被测代码创建的实例

标签 c++ unit-testing googletest googlemock

我已经创建了一个接口(interface)(这里是一个例子):

class DataStream
{
    virtual std::string read(std::string terminator) = 0;
    virtual size_t write(std::string data) = 0;
};

为此存在一个具体的实现,例如:

class SerialDataStream : public DataStream
{
public:
    // NOTE: This constructor will throw an exception if the
    // serial port cannot be opened.
    SerialDataStream(string port, int baudrate);
    std::string read(std::string terminator);
    size_t write(std::string data);
}

以及使用的接口(interface),例如:

class SomeThing
{
public:
    SomeThing(std::shared_ptr<DataStream> stream);
}

使用 GoogleMock,测试 SomeThing 类非常简单,您需要做的就是为接口(interface)创建一个模拟实现,例如:

class MockDataStream : public DataStream
{
public:
    MOCK_METHOD1(read, size_t(std::vector<uint8_t>&));
    MOCK_METHOD1(write, size_t(std::vector<uint8_t>&));
}

测试看起来像这样:

std::shared_ptr<MockDataStream> mock_stream(nullptr);
mock_stream = std::make_shared<MockDataStream>();
EXPECT_CALL(*mock_stream, write("START")).Times(AtLeast(1));
EXPECT_CALL(*mock_stream, read("\n")).Times(AtLeast(1));
SomeThing some_thing = SomeThing(mock_stream);

这很酷,因为它可以让我轻松地对 SomeThing 类如何使用 DataStream 接口(interface)进行单元测试。

但是,也存在一些代码,其工作是创建新的(具体的)DataStream 对象,我发现使用 GoogleMock 来测试它有点棘手。例如,这里是一些需要测试的代码片段:

std::shared_ptr<DataStream> datastream(nullptr);

// Try and open the serial port:
try
{
    std::shared_ptr<SerialDataStream> serialstream =
        std::make_shared<SerialDataStream>("/dev/tty99", 115200);
}
catch (...) 
{
    // Returns a nullptr
    return datastream;
}

// Check if there is a known device on the other end:
datastream = std::static_pointer_cast<DataStream>(serialstream);
if (!device_is_connected(datastream))
{
    datastream = nullptr;
}
return datastream;

我正在努力寻找一种有效的方法来使用 GoogleMock 测试此代码:

  1. 我想模拟(SerialDataStream 的)构造函数,以便它抛出异常并按预期执行失败路径。
  2. 我想测试私有(private) API“device_is_connected”使用新创建的数据流对象的成功路径。

除了创建一个伪造的 SerialDataStream 实现并使用依赖注入(inject)来测试创建具体 DataStream 对象的代码之外,我别无选择吗?

如果是这种情况,我只需要将 API“device_is_connected”公开,这样我就可以使用接口(interface)的模拟实现(如上所述)简单地对其进行测试,例如:

datastream.write("DISCOVER");
string response = datastream.read("\n");
if (discovery_ok(response))
{ 
    // do stuff
}

我相当确定我已经回答了我自己的问题并且别无选择,只能伪造 SerialDataStream 类并使用依赖项注入(inject),并公开私有(private) API 并通过 GoogleMock 简单地测试它们,但我愿意接受建议如果有更好的方法我可以/应该在这里做事。

最佳答案

看着您提供的代码片段,我发现自己在问:
该功能究竟应该做什么?好像是
(1) 创建一个 SerialDataStream 和
(2) 检查设备是否已连接。

您可以将函数分成两个(可单独测试的)部分。
关于如何处理 std::shared_ptr<SerialDataStream> serialstream = std::make_shared<SerialDataStream>("/dev/tty99", 115200); 仍然存在问题- 在某些时候,您需要解决那里的(隐藏的)

我同意你的看法——依赖注入(inject)可能是解决方案。将最终负责创建的任何类或函数转换为模板类/函数将允许编写你(例如)

template<typename T>
std::shared_ptr<DataStream> createDatastream()
{
    std::shared_ptr<DataStream> datastream(nullptr);
    std::shared_ptr<T> datastream = std::make_shared<T>("/dev/tty99", 115200);
    return datastream;
}

然后用SerialDataStream实例化类/函数在您的应用程序中,同时使用 MockDataStream测试函数。

关于c++ - 使用 GoogleMock 模拟由被测代码创建的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52311323/

相关文章:

c++ - 我如何在 C++ 中找到堆中的特定索引?

c++ - 如何正确使用dirent.h

c++ - UBLAS 矩阵查找单元格的周围值?

java - 使用 gradle 为各个单元测试生成 Jacoco 代码覆盖率报告

c++ - Google 测试中的 EXPECT_NO_DEATH()

c++ - openGL何时以及如何计算F_depth(深度值)

silverlight - MS Fakes - 未在/reference 选项中指定 extern 别名

java - 如何使用easymock模拟类中的静态方法?

c - 如何测试C中函数调用的顺序?

c++ - 需要帮助谷歌测试一个唯一的 Id 生成器