2014-09-10 50 views
1

我进入一个项目,我们有一个大的代码库,目前它没有任何单元测试框架。我们正在处理的代码将最终运行在一个框上,交换机/路由器/防火墙。Gtest与大C和C++代码库

所以我正在研究一段需要使用Gtest进行单元测试的代码。 我有这个问题是嘲笑变量以测试函数本身。 例如,我有一个函数,它使用4个指针指向不同的对象,并使用几个全局变量。为了测试代码中的不同路径,我需要初始化因变量的几乎整个状态machien/values。 增加了复杂性,因为它在大型代码库中是真实的,我写的这个函数/方法使用了一些其他需要测试的例程/方法。每个人都需要进行单向测试,每个人都有自己的依赖关系。 我不确定我是否正在处理这个问题,或者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 
} 

像this.How做我测试所有这些功能,A-F?什么是好策略?

+0

为什么在编写C代码时标记为C++?顺便说一下全局变量是一个坏主意 – 2014-09-10 19:06:03

+0

代码库有C和C++两种,我知道全局变量是一个坏主意。这就是它现在的设计方法。要忍受它:) – 2014-09-10 20:18:50

+0

测试大型/复杂代码是不容易的。您需要编写能够处理代码的测试,并且经常设置各种对象。在我工作的地方,编写测试的时间通常是实际开发真实代码所需时间的2-5倍。只有当测试代码非常简单时,这个数字才会下降到1.5或2倍。有时测试代码可能需要10次以上的原始代码写入。 – 2014-09-10 20:20:35

回答

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++,您将使用引用而不是指针,并可能将所需的外部对象传递给类构造函数。这也被称为依赖注入,确保研究这个术语以获得透彻的理解。

测试接触全局变量函数的另一种方法是使用测试的设置函数将全局重置为已知状态。这仍然需要在全球进行联系,但这可能很困难。不使用全局变量可能会使代码库变得更好,因此接受它也会发送错误的消息。

+0

有一点需要注意的是,另外将相关的全局变量分组到结构中将有助于减少需要传递给函数的参数数量。如果不这样做,您可以轻松完成占用大量参数的功能。 – 2014-09-11 06:25:11

+0

在全局代码中需要注意的另一件事是以函数静态变量或线程局部变量的形式“隐藏的全局变量”。 – 2014-09-11 06:28:42

0

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

对于你想测试你应该看看

  • 它访问全局的任何全局函数。
  • 它使用的参数。
  • 它调用的函数。

然后考虑:

  • 转换它调用来调用一个或多个接口的功能,并且通过那些作为参数。
  • 将全局变量转换为参数或接口上的函数调用。

如果你的函数是一个对象,而不是全局函数上的功能,您还可以考虑:

  • 使全局成员变量,并将它们传递给构造
  • 使得功能它调用虚拟成员函数

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

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

(是的,我在大规模代码基础上采用了这种方法......它通常很痛苦,但一旦得到习惯了它,代码开始得到更多的测试 - 事情会改善。)