如何替换time()函数来测试生产库?

时间:2011-01-11 09:47:08

标签: c unit-testing testing time cross-platform

我想为我的C库编写黑盒测试,它使用标准的C时间函数(time(),localtime(),gmtime()等)在其输出中使用时间戳。输出是编码的,所以我需要用一些测试模拟或“后门”替换那些时间函数,这样我就可以控制我的库从time()函数而不是当前系统时间获取的值,所以我可以在我的测试中正确编写检查。

实现这一目标的最佳方法是什么?我可以在生产库中使用这样的支持(可能有一些旋钮?),或者我应该以2种形式编译我的库:使用实时()函数进行生产以及使用我自己的受控时间()函数进行测试?

我对跨平台解决方案感兴趣,所以像LD_PRELOAD这样的技巧对我来说不是一个解决方案。

更新:我明白我应该提供一些实时()函数的包装器,我会做那些包装器。我的问题是:我可以在生产库中使用那些并在运行时控制它们,或者我永远不应该这样做并且总是应该编译2个库:一个用于生产,第二个用于测试?

3 个答案:

答案 0 :(得分:2)

过去,我为嵌入式C项目完成此操作的方法是创建两个项目/配置 一种配置适用于生产环境,包含所有生产代码(包括依赖项),另一种配置用于单元测试,包含测试驱动程序和所有模拟。这两种配置共享了要测试的代码的来源 在单元测试环境中,我只是链接到被测代码所需的所有外部函数的模拟或伪造。

有几种方法可以将待测代码链接到它所需的模拟:

  • 您只需向链接器提供带有模拟的对象文件。大多数链接器将首先使用它们在指定的目标文件中找到的名称,并尝试使用库中的名称来解析它们。一些链接器遵守在命令行上指定目标文件和库的顺序,因此在这些情况下,应确保在库之前指定了模拟(如果您指定库)。
    对于C标准库中的函数,这在技术上会导致未定义的行为,但在大多数情况下,即使对于这些函数,它也能很好地工作。
  • 您可以创建一组包装器宏,您可以使用define切换它们。例如:

    #ifdef UNIT_TEST
      #define my_time time_mock
    #else
      #define my_time time
    #endif
    
  • 您创建了一组包装函数(在不同的源文件中实现),并提供这些函数的模拟。这有一个轻微的缺点,即如果不使用上述子弹的技术之一就无法对这些功能进行单元测试。

更新:即使您的生产代码进入库,单元测试配置也应生成(一个或多个)可执行文件。
单元测试代码不应包含在生产库中(尽管您可以考虑将其包含在源代码分发中),因为它只会增加可能导致错误的额外行李。如果您的某个客户意外地在单元测试模式下切换库并开始抱怨它已损坏,您是否愿意?

答案 1 :(得分:1)

我会将调用包装为静态变量(unitTest)。因此,您可以随时从配置文件初始化该行为。

time_t myTime( time_t * timer ) 
{
    if ( unitTest ) {
        return TIME_TEST;
    }
    return time( timer );
}

答案 2 :(得分:1)

(我认为你不是在询问实现细节,而是要让它成为编译时,部署时或运行时配置方面。)

我认为这取决于。

如果你有一个众所周知的配置机制(无论是配置文件,环境变量,命令行参数,等等),我会在那里添加它作为配置项。然后,您可以在生产中使用与测试中完全相同的二进制文件。一些组织非常严格地要求这样做。

由于您在生产中永远不需要该功能,我建议将其作为编译时配置项,以便您可以100%确定您永远不会错误配置生产中的应用程序,因为不支持该功能。 (当然,你必须绝对确保你永远不会将为编译而编译的二进制文件部署到生产中。)我认为条件定义/条件编译是一个不错的选择。

这就是关于它的所有内容,不是吗?