【问题标题】:Proper approach to change a class functionality for unit testing?更改单元测试的类功能的正确方法?
【发布时间】:2019-01-09 23:08:49
【问题描述】:

我正在开发一个旧的大型 C++ 代码库,并且一直在为缺少它们的组件创建单元测试。

为了测试目的模拟这些类的功能的正确方法是什么?目前我正在使用虚函数,在我的测试模块中,我从基础“生产”类派生一个模拟类,并根据需要覆盖功能。

这是一个例子:

生产.cpp

class Production {
protected:
    int Servers = 0;
public:

    virtual bool IsValInRegistry(const std::string& regVal);
};

bool Production::IsValInRegistry(const std::string& regVal)
{
    HRESULT hr = GOOD;
    hr = WinSysCallToRegistry(regVal);

    if (HR)
        return true;
    else
        return false;
}

模拟.cpp

class Mock : public Production {
public:
    bool IsValInRegistry(const std::string& regVal) override final;
};

Mock::IsValInRegistry(const std::string& regVal)
{
    return true;
}

这是正确的前进方式吗?我担心如果我引入太多 virtual 函数,我可能会看到我想避免的性能下降。如果这个virutal模型不理想,有什么好的方法?

【问题讨论】:

  • 我只做过Java,但是你知道依赖注入是怎么工作的吗?
  • 在现有的大型遗留代码库中,重构代码以使用依赖注入本身就是一项艰巨的工作。
  • 唯一“正确”的方法是正确工作的方法,这是底线。是否是虚函数;或者,重新定义一些相关的类,以便测试类认为它使用的是真实的类,而是使用返回模拟数据的类;或出于测试目的故意和受控违反单一定义规则;或预处理器技巧——一切都是公平的游戏。什么都能完成工作。我已经使用了所有这些方法,然后在不同的时间使用了一些。
  • 你可以使用#define MOCK_VIRTUAL final。然后当嘲笑它是非最终的;当不嘲笑时,它是最终的,因此被虚拟化。保留 RTTI,以减少不同行为的机会。

标签: c++ unit-testing


【解决方案1】:

如果你想在不影响性能的情况下这样做,你可能想尝试像这样的编译时模拟:

class Production {
protected:
    int Servers = 0;
public:

    bool IsValInRegistry(const std::string& regVal);
};

bool Production::IsValInRegistry(const std::string& regVal)
{
#ifdef USE_MOCK_PRODUCTION
    return true;
#else
    HRESULT hr = GOOD;
    hr = WinSysCallToRegistry(regVal);

    if (HR)
        return true;
    else
        return false;
#endif
}

这将需要使用所需的标志重新编译您需要的测试,但生产版本将保持不变。因此,您可以花在运行这些单元测试上只是时间问题。

【讨论】:

  • 但这绝对是最后的选择。您希望您的生产代码成为您的生产代码,仅此而已。
猜你喜欢
  • 1970-01-01
  • 2016-03-25
  • 1970-01-01
  • 2022-01-14
  • 2015-07-24
  • 2015-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多