小编mpo*_*llo的帖子

如何将单元测试引入大型遗留(C/C++)代码库?

我们有一个用C语言编写的大型多平台应用程序(只有少量但不断增长的C++)多年来,它已经发展了许多你期望在大型C/C++应用程序中使用的功能:

  • #ifdef 地狱
  • 大文件使得难以隔离可测试代码
  • 功能过于复杂,无法轻松测试

由于此代码是针对嵌入式设备的,因此在实际目标上运行它需要大量开销.因此,我们希望在本地系统上以快速周期进行更多的开发和测试.但我们希望避免"在您的系统上复制/粘贴到.c文件,修复错误,复制/粘贴"的经典策略.如果开发人员要麻烦这样做,我们希望以后能够重新创建相同的测试,并以自动方式运行.

这是我们的问题:为了使代码重构更加模块化,我们需要它更易于测试.但是为了引入自动化单元测试,我们需要它更加模块化.

一个问题是,由于我们的文件太大,我们可能在文件中有一个函数调用一个文件中的函数,我们需要将它们存根以进行良好的单元测试.看起来这不是一个问题,因为我们的代码变得更加模块化,但这还有很长的路要走.

我们想到的一件事是用注释标记"已知可测试"的源代码.然后我们可以为可测试代码编写脚本扫描源文件,将其编译在单独的文件中,并将其与单元测试链接.我们可以在修复缺陷和添加更多功能时慢慢引入单元测试.

但是,有人担心维护这个方案(以及所有必需的存根函数)将变得太麻烦,开发人员将停止维护单元测试.所以另一种方法是使用一个工具,为所有代码自动生成存根,并将文件链接到该工具.(我们发现这样做的唯一工具是昂贵的商业产品)但是这种方法似乎要求我们所有的代码在我们开始之前都要更加模块化,因为只有外部调用可以被删除.

就个人而言,我宁愿让开发人员考虑他们的外部依赖关系并智能地编写他们自己的存根.但是,对于一个可怕的过度生长的10000行文件来说,这可能是压倒性的.可能很难说服开发人员他们需要为所有外部依赖项维护存根,但这是正确的方法吗?(我听到的另一个论点是子系统的维护者应该维护子系统的存根.但是我想知道"强迫"开发人员编写自己的存根会导致更好的单元测试吗?)

#ifdefs,当然,再添全尺寸的问题.

我们已经研究了几个基于C/C++的单元测试框架,并且有很多选项看起来很好.但是我们还没有找到任何方法来缓解从"没有单元测试的代码毛球"到"单元可测试代码"的过渡.

所以这是我对其他任何经历过这个问题的人的问题:

  • 什么是一个好的起点?我们是朝着正确的方向前进,还是我们错过了一些明显的东西?
  • 哪些工具可能有助于过渡?(最好是免费/开源,因为我们现在的预算大致为"零")

注意,我们的构建环境基于Linux/UNIX,因此我们不能使用任何仅限Windows的工具.

c c++ unix legacy unit-testing

73
推荐指数
6
解决办法
1万
查看次数

使用cmake,您将如何禁用源内构建?

我想禁止人们使用生成的CMake文件混乱我们的源代码树...更重要的是,不允许他们踩到Makefiles不属于我们使用CMake的同一构建过程的现有内容.(最好不要问)

我想出这样做的方法是在我的顶部有几行CMakeLists.txt,如下所示:

if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")
   message(SEND_ERROR "In-source builds are not allowed.")
endif("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")
Run Code Online (Sandbox Code Playgroud)

但是,这样做似乎太冗长了.此外,如果我尝试进行源内构建,它仍然会在引发错误之前创建CMakeFiles/目录和CMakeCache.txt源树中的文件.

我错过了更好的方法吗?

build cmake

41
推荐指数
4
解决办法
1万
查看次数

为什么不是新的(特定于位宽)printf()格式选项字符串作为C99的一部分?

在研究如何printf()在C中执行跨平台格式字符串时(也就是说,考虑到我希望每个整数参数printf()应该是的位数),我在维基百科文章的这一部分中进行了讨论printf().本文讨论了可以传递给printf()格式化字符串的非标准选项,例如(似乎是特定于Microsoft的扩展):

printf("%I32d\n", my32bitInt);
Run Code Online (Sandbox Code Playgroud)

它接着说:

ISO C99包括inttypes.h头文件,其中包含许多用于独立于平台的printf编码的宏.

...然后列出一组可在所述标题中找到的宏.查看头文件,使用它们我必须写:

 printf("%"PRId32"\n", my32bitInt);
Run Code Online (Sandbox Code Playgroud)

我的问题是:我错过了什么吗?这真的是标准的C99方式吗?如果是这样,为什么?(虽然我从未见过以这种方式使用格式字符串的代码并不感到惊讶,因为它看起来很麻烦......)

c printf types c99 format-specifiers

17
推荐指数
2
解决办法
7350
查看次数

使用C用户空间代码从Linux/proc接口读取的最佳方法是什么?

根据man 5 proc,可以使用/proc文件系统访问Linux上的以下信息:

   /proc/[pid]/maps
          A file containing the currently mapped memory regions and their access
          permissions.

          The format is:

          address           perms offset  dev   inode   pathname
          08048000-08056000 r-xp 00000000 03:0c 64593   /usr/sbin/gpm
          08056000-08058000 rw-p 0000d000 03:0c 64593   /usr/sbin/gpm
          08058000-0805b000 rwxp 00000000 00:00 0
          40000000-40013000 r-xp 00000000 03:0c 4165    /lib/ld-2.2.4.so
          40013000-40015000 rw-p 00012000 03:0c 4165    /lib/ld-2.2.4.so
          4001f000-40135000 r-xp 00000000 03:0c 45494   /lib/libc-2.2.4.so
          40135000-4013e000 rw-p 00115000 03:0c 45494   /lib/libc-2.2.4.so
          4013e000-40142000 rw-p 00000000 00:00 0
          bffff000-c0000000 rwxp 00000000 00:00 0 …
Run Code Online (Sandbox Code Playgroud)

c linux memory memory-management linux-kernel

15
推荐指数
1
解决办法
7101
查看次数

IPv6链路本地地址格式

我正在开展一个与网络/压缩相关的项目.其中一台机器是Windows Vista,已经配置了IPv6.

当我尝试时ipconfig,我会看到以下格式的地址:fe80::9dc8:72fa:aacd:76e2%10

但是当我尝试从另一台机器ping这台机器时ping fe80::9dc8:72fa:aacd:76e2%10,我收到以下错误:

Ping request could not find host fe80::9dc8:72fa:e327:76e2%10.
Please check the name and try again.

任何想法/评论都非常有帮助.

windows networking tcp ping ipv6

14
推荐指数
2
解决办法
2万
查看次数

我可以使用http隧道通过带防火墙的代理ping或traceroute吗?

我不知道是否有办法ping我的局域网代理之外的目标只通过squid代理接受Http请求...我在某处读到了处理这种问题的一种方法是使用一个http隧道,以便代理仍将请求视为Http请求.我可以使用它来ping,例如www.google.com,否则会出现以下错误,因为防火墙拒绝了请求:

$ ping www.google.com
ping: unknown host www.google.com
Run Code Online (Sandbox Code Playgroud)

如果是这样,它是如何完成的?

我已经安装了httptunnel.Any帮助如何使用它将非常感激.

networking tunneling http-tunneling

12
推荐指数
1
解决办法
3万
查看次数

为清晰起见,是否应使用返回类型的无用类型限定符?

当我们在头文件中有原型时,我们的静态分析工具会抱怨"返回类型上的无用类型限定符",例如:

const int foo();
Run Code Online (Sandbox Code Playgroud)

我们这样定义它是因为函数返回一个永远不会改变的常量,认为API似乎更清晰const.

我觉得这类似于为了清楚明确地将全局变量初始化为零,即使C标准已经声明如果未明确初始化所有全局变量将被初始化为零.在一天结束时,它真的没关系.(但静态分析工具并没有抱怨.)

我的问题是,有什么理由可以导致问题吗?我们是否应该忽略该工具产生的错误,或者我们是否应该以不太清晰和一致的API的可能成本来安抚该工具?(它返回const char*该工具没有问题的其他常量.)

c static-analysis coding-style const

11
推荐指数
2
解决办法
5604
查看次数

如何使用反射从int转换为十进制?

我有一些代码(工作正常)看起来像这样:

        int integer = 42;
        decimal? castTo = integer;
Run Code Online (Sandbox Code Playgroud)

然后我想用反射做类似的事情,有些代码看起来像这样:

object value = source; // source was an int originally
var parameters = new object[1];    
    ...
    parameters[0] = value;
    var setMethod = property.GetSetMethod();     
    // Call the set method, which takes a decimal? as a parameter
    setMethod.Invoke(o, parameters);  
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我得到:

failed: System.ArgumentException : Object of type 'System.Int32' cannot be converted to type 'System.Nullable`1[System.Decimal]'.
    at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
    at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature …
Run Code Online (Sandbox Code Playgroud)

c# reflection type-conversion

11
推荐指数
2
解决办法
7050
查看次数

IPv5去哪儿了?

既然我们都在转向IPv6,无论我们是否愿意,我都会问:IPv5发生了什么?对于它的哥哥来说,它不够酷,还是在那个规范上做了其他事情?

networking standards ipv4 ipv6

11
推荐指数
2
解决办法
7982
查看次数

使用cmake,如何确定每种构建类型的默认编译器标志?

我正在尝试配置我的构建系统,以便我的发布版本不包含额外的调试.但我无法在CMake文档中找到任何列出默认情况下每个构建类型使用哪些编译器标志的内容,而我宁愿不发明自己的做事方式.

这个功能是否已经存在?如果不采用试验和错误,我如何确定默认情况下为各种构建类型使用哪些标志?

cmake

11
推荐指数
1
解决办法
1万
查看次数