Gtest具有大型C和C ++代码库

时间:2014-09-10 19:03:50

标签: c++ c unit-testing googletest cxxtest

我进入了一个项目,我们拥有一个庞大的代码库,目前它根本没有单元测试框架。我们正在处理的代码最终会在一个充当交换机/路由器/防火墙的盒子上运行。

所以我正在编写一段需要使用Gtest进行单元测试的代码。 我遇到的问题是模拟变量以测试函数本身。 例如,我有一个函数,它使用4个不同对象的指针并使用几个全局变量。为了测试代码中的不同路径,我需要初始化几乎整个状态机制/因变量的值。 在大型代码库中增加了复杂性,我编写的这个函数/方法使用了一堆其他需要测试的例程/方法。每个都需要进行单一测试,每个都有自己的依赖关系。 我不确定我是否正确处理问题,或者gtest可能不是测试如此大型代码库的正确工具。

如果有人有说测试的经验,说一个电话堆栈说

function A {
    code 
    code
    function B
    code 
    code
    function C
    code
}

function B
{
    function D
    code
    function E
}

function C{
    code
    function F
    function G
    code
}
像这样的事情。我如何测试所有这些功能A-F ??什么是好策略?

2 个答案:

答案 0 :(得分:2)

首先要重构代码,以便隔离可测试的部分。特别是,这意味着删除对全局变量的访问。例如:

int global;
int function() {
    int r = foo();
    global += r / 2;
    bar(r);
    return 42;
}

删除全局对象意味着将其转换为输入参数:

int real_function(int* target) {
    assert(target);
    int r = foo();
    *target += r / 2;
    bar(r);
    return 42;
}

然后剩下的代码当然会停止编译,所以你添加一个向后兼容的cludge:

int global_bar;
// @deprecated, use real_function() directly
int function() {
    return real_function(&global_bar);
}

使用它,你升级调用链,提取依赖关系,并希望有一天删除对需要全局变量的变量的最后一次调用。与此同时,您可以为不再依赖于全局内容的函数编写测试。请注意,对于C ++,您将使用引用而不是指针,并可能将所需的外部对象传递给类构造函数。这也称为依赖注入,请务必研究该术语以便全面了解。

测试接触全局变量的函数的另一种方法是使用测试的setup函数将全局重置为已知状态。这仍然需要在全球范围内进行链接,这可能会很困难。并且不使用全局变量可能会使代码库首先变得更好,所以接受它也会发送错误的消息。

答案 1 :(得分:0)

Ulrich Eckhardt基本上说,“你需要摆脱全局变量以制作易于测试的代码”。但你真的应该走得更远。

对于您要测试的任何全局函数,您应该查看

  • 它访问的全局变量。
  • 它使用的参数。
  • 它所调用的功能。

然后考虑:

  • 将其调用的函数转换为对一个或多个接口的调用,并将其作为参数传递。
  • 将全局变量转换为接口上的参数或函数调用。

如果您的函数是对象而不是全局函数的函数,则可以另外考虑:

  • 制作全局成员变量,并将它们传递给构造函数
  • 制作称为虚拟成员函数的函数

我认为使函数可测试的最后一件事是它是否属于一个类。

一旦解决了所有这些问题,您通常可以轻松地模拟所需的位。如果您正在使用gtest,您可以使用gmock来简化这一过程。 (我之前使用gmock和gtest非常无痛。)

(是的,我之前在大型代码库上采用了这种方法......开始时通常非常痛苦,但是一旦你习惯它并且代码开始变得更加可测试 - 事情就会好转。 )