在函数/类声明附近编写C++单元测试



当谈到在C++中为函数或类编写单元测试时,在与原始声明和定义(例如math_test.cpp for math.hpp/math.cpp)分开的源文件中编写它们似乎很流行。我想知道在声明附近编写它们是否会更好,原因如下:

  • 用户可以从单元测试中看到如何使用函数或类
  • 开发人员可以清楚地判断一个函数或类是否有单元测试

例如,我想知道我是否可以对头文件中的函数声明进行单元测试,如下所示:

// plus.hpp
int plus(int a, int b);
UNITTEST{ assert(plus(1, 2) == 3); }

而源文件与往常一样:

// plus.cpp 
int plus(int a, int b) { return a + b; }

只有当我定义了一个特定的宏(例如ENABLE_UNITTEST)时,我才期望UNITTEST代码由编译器评估并由测试运行程序可执行文件执行。

我的问题是:

  1. 在这样的声明附近编写单元测试是一种好的做法吗
  2. 是否有任何现有的C++测试框架支持编写这样的测试?(我认为如果框架没有正确实现,当plus.hpp包含在多个源文件中时,会导致重新定义错误)
  3. 如果答案为2。是否,有可能实现这样的测试框架吗

在这样的声明附近编写单元测试是一种好的做法吗?

不,不是。单元测试代码比实际代码多的情况并不少见。将两者混合在一起会使系统更难维护和重构。

将单元测试放在主代码中的想法对于像您这样的小代码示例来说很有吸引力。然而,在许多情况下,您的单元测试代码很容易是实际代码的三倍甚至四倍,尤其是在您的目标是高代码覆盖率的情况下。添加的代码的简单大小及其代码内文档将使人们更难更改您的系统。

此外,一些单元测试需要在运行过程中维护状态(通用测试框架的设置和拆卸功能处理此问题)。将状态占位符与有效负载代码混合使用会使问题更加复杂。

是否有任何现有的C++测试框架支持编写这样的测试?

据我所知并非如此。

如果答案为2。是否,有可能实现这样的测试框架吗?

这当然是可能的——例如,您可以使用预处理器宏和条件编译来从"有效负载"代码中提取单元测试,并分别进行编译。不过,我认为这并不可取。

我认为归根结底,对于您给出的例子来说,这似乎是完全合理的。然而,我所从事的项目有几个包含数百行的测试文件。人们通常也不只是测试一件事,而是将其置于过多的测试条件中。

如果你的测试用例每次都比一两行长(或者有多个测试),你的做事方式会很快变得一团糟。更不用说试图查找代码和一般可读性会大大降低。

是否有任何现有的C++测试框架支持编写这样的测试?(我认为如果框架没有正确实现,当plus.hpp包含在多个源文件中时,会导致重新定义错误)

您可以用许多现有的框架(如果不是全部的话)来实现这种方式,例如谷歌测试:

int plus(int a, int b);
#ifdef UNITTEST_ENABLED
TEST(Functions,plus)
{
    EXPECT_EQ( 4, plus( 2, 2 ) );
}
#endif // UNITTEST_ENABLED

您只需要正确配置您的构建系统,就可以使用宏UNITTEST_ENABLED定义的编译测试源

尽管我同意@dasblinkenlight的回答,并认为这不是将测试代码与常规源代码混合使用的好做法。例如,当你在代码中正确地覆盖plus()函数时,你应该检查阳性与阳性、阳性与阴性、阴性与阴性以及角大小写(max-int+0)等。如果你正确地这样做,你的实际函数代码将很好地隐藏在测试中,因此你的源代码将变得不可读。

更糟糕的是,将单元测试放在头中。与上面相同的原因加上标头应该只有声明,而不是实际的代码。

最新更新