2016-08-03 81 views
2

即时通讯非常好奇人们的意见在什么方式与硬件接口的软件侧应用程序应单元测试。单元测试应用程序接口到硬件 - 模拟或不模拟

例如,软件应用程序“连接”的主要类将构建USB设备的句柄。

我想测试“连接”类的基本功能,比如说“OpenConnection”,它会尝试连接到USB硬件设备。

到目前为止我已经构建了一个MOCK硬件设备,并且在我的连接类中包含了一个编译器标志,所以如果它内置在单元测试模式下,它将使用模拟对象,否则它会使用实际的硬件接口。

参见下面的例子

class TConnection 
{ 
public: 
    static TConnection* GetConnection(); 
    static void Shutdown(); 

    bool DidInitialise(); 

    bool Write(uint8_t* _pu8_buffer); 
    bool Read(uint8_t* _pu8_buffer); 

protected: 
    TConnection(); 
    virtual ~TConnection(); 
    bool init(); 

private: 
    static TConnection* mp_padConnection; 
    static bool mb_DidInitialise; 

#ifdef _UNIT_TEST_BUILD 
    static mock_device* mp_handle; 
#else 
    static device* mp_handle; 
#endif 
}; 

然后在源文件中包括我像

#include "connection.h" 

#ifdef _UNIT_TEST_BUILD 
    mock_device* TConnection::mp_handle = nullptr; 
#else 
    device* TConnection::mp_handle = nullptr; 
#endif // _UNIT_TEST_BUILD 

TConnection::TConnection() 
{ 
    ... 
    init(); 
    ... 
} 

bool TConnection::init() 
{ 
    mp_handle = hid_open(_VENDOR_ID, _PRODUCT_ID, nullptr); 
    if (mp_hidHandle == nullptr) { 
     return false; 
    } 
    if (hid_set_nonblocking(mp_hidHandle, _DISABLE_NB) == _ERROR_CODE) { 
     return false; 
    } 
    return true; 
} 

我真的不喜欢我的代码的唯一的事情就是我的实际连接类包含测试代码。我更喜欢他们分开。我也不同意拥有一个全新的模拟连接类,它仅仅是为了单元测试的目的而编写的,它让我觉得我只是在写一些按照预期工作的东西。

所以我问,什么是预先测试的这样一类

谢谢您的时间和建议更好的方法

回答

5

您可以避免使用依赖注入向您的类添加测试代码。创建一个接口IDevice并使类Device实现该接口。然后,在类TConnection中,使用指向此接口的指针而不是Device类型的成员。同时创建一个辅助方法,它允许您设置一个新的设备,是这样的:现在

void setDevice(IDevice *device); 

,为您的生产代码的简单使用Device类的实例,而在你的测试代码使用setDevice交换实现设备的与一个模拟对象。这个模拟对象将是类MockDevice的一个实例,它也将实现接口IDevice。这样你可以在测试中改变实现并使用模拟类。由于您已经使用gtest,所以我建议您不要自己编写模拟类,而应使用C++嘲笑框架gmock(它完全兼容gtest)。这样,您还需要创建一个单独的类,但几乎所有内容都将由模拟框架处理。你所需要做的就是定义模拟方法。创建一个额外的界面和模拟类似乎起初是过度的,但从长远来看,它肯定会带来回报。如果你想做任何认真的代码测试,学习使用接口,依赖注入和模拟类是非常重要的。检查文档了解更多信息:

https://github.com/google/googlemock/blob/master/googlemock/docs/CheatSheet.md

+0

您好Marko,我想您刚刚为我提供了我的理想设计,谢谢!我非常喜欢这种界面方法。在我的课堂上嵌入了测试/模拟代码时,它非常抽象。我现在要尝试这种设计,但我相信它正是我所需要的。 – Spirit

3

我个人有模拟无论是作为单独的类,或部分的测试代码。为了区分模拟库和实际库,我将在构建脚本中进行更改,我假设这将包括链接到库的测试文件(和模拟)

创建一个单独的类不是浪费精力。它应该按照预期行事,但这可以简化为测试所需的最低限度。更有趣的是让类生成错误事件,以确保您的代码正确处理这些事件。另一种选择是有时要等待发生错误,我不建议这样做。强烈建议在主题

两本书:

+0

谢谢你的意见的Eirik,我很欣赏的反馈。不过,我只是觉得当我嘲笑我的主要课程,并且这样做时,我忽视了我的连接类的实际测试。但我感谢你的看法,我可以看到有一个单独的ConnectionMock可能是我应该去的方式:) – Spirit

+1

我添加了一些书籍建议,我发现有帮助。基本上,如果做得对,模拟应该和记录功能中的测试代码一样重要。 –

+0

非常感谢Eirik的书籍,它们看起来很有趣。 Ive既然下了他们俩的订单:) – Spirit