Googletest C++ 是一个单元测试框架。这意味着它旨在测试 C++ API 的实现。它不适用于测试程序。
出于实际目的,C++ API 就是您在 C++ 头文件中获得的内容。这种 API 的实现可能是:
- 只是头文件本身。(实现完全是内联的)
- 头文件加上一个 C++ 源文件
- 头文件加上一堆C++源文件
概括地说,C++ API 的实现是一个头文件加上 0 个或多个源文件。
假设您的程序my_prog
调用了您或您的团队为管理 Gizmo 而开发的 API。实现类似于:
gizmo.h
[gizmo_0.cpp,...gizmo_N.cpp]
其中[...]
意味着可选...
也许my_prog
依赖于您或您的团队负责的其他 API,但我们将只使用一个。my_prog
通过以下方式使用 Gizmo API:-
#include "gizmo.h"
在一些源文件中使用。
- 编译
[gizmo_0.cpp,...gizmo_N.cpp]
源文件,如果有的话。
- 链接
[gizmo_0.o,...gizmo_N.o]
目标文件(如果有)。
(gizmo_0.obj
等,如果你在 Windows 上)
使用 Googletest 测试您的 gizmo API 实现应该确认此实现是正确的,独立于my_prog
或任何其他依赖它来管理 gizmo 的程序。因此,将实现的单元测试合并到实现中 my_prog
是被误导的:-
也许您的同事编写了另一个程序,该程序也需要使用此实现来管理 Gizmo。也许你再写一个。编写这个其他程序的人是否应该重复将 Gizmo 单元测试合并到其中的过程 - 相同的?不同的?- 并使程序有条件地编译为小发明测试工具或在现实生活中应该是什么?
你怎么知道小发明的实现没有以某种方式与独特的功能纠缠在一起my_prog
,或者与以相同方式使用的其他一些API的实现纠缠在一起my_prog
——所以当你或其他人试图在另一个程序中重用它时,它打破或行为错误?
没有任何依赖此 Gizmo 实现的程序可以进行单元测试。有条件地my_prog
编译不同的main
函数,以便它可以兼作 Gizmo 库的单元测试工具,这类似于在牛仔裤的裤裆上切一个洞让你的头穿过。
您应该对 gizmo 库进行单元测试的方式是编写一个作为该库的测试工具的程序,仅此而已。比如说,这个程序gizmo_test
将使用 gizmo API,就像任何其他程序使用它一样,但其唯一目的是测试 gizmo 库。所有这gizmo_test
一切都是通过调用它的 API 来执行 Gizmo 库的测试。
作为第一个近似值,GoogleTest 的配方gizmo_test
是:
写一个头文件,gizmo_test.h
#include "gizmo.h"
在里面
#include <gtest/gtest.h>
在里面
然后在其中编写您的 Googletest 测试用例
编写如下源文件gizmo_test.cpp
#include "gizmo_test.h"
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
创建一个项目gizmo_test
- 在 Eclipse 或您使用的任何开发环境或构建系统中 -gizmo_test
通过以下方式构建可执行文件:
- 编译源文件
gizmo_test.cpp
+[gizmo_0.cpp,...gizmo_N.cpp]
- 链接生成的目标文件
gizmo_test.o
+ [gizmo_0.o,...gizmo_N.o]
,以及libgtest
您的 Gizmo 库所依赖的任何其他库
你有两个项目。一个做my_prog
的,一个做的gizmo_test
。在您的开发环境或构建系统中,使构建my_prog
依赖于构建gizmo_test
,这样当您更改任何影响 Gizmo 库和重新构建my_prog
的内容时,gizmo_test
首先重新构建。
这是第一个近似值。您是否注意到不久前我开始谈论您的 Gizmo库?这就是你所拥有的(或应该拥有的)。在 C++ 和编程中,API 的实现称为库。
也许您还注意到gizmo_test
. [gizmo_0.cpp,...gizmo_N.cpp]
您在两个项目中拥有相同的 Gizmo 源文件集
。因此,您可以在两个项目中以不同方式编辑、编译和链接它们。并且它们将在两个项目中被编译,或者不同,这是错误的,或者相同,这是没有意义的。
当然,如果这组源文件是空的——gizmo 库什么都不是gizmo.h
——就没有这样的问题。但如果它不是空的,那就有。
如您所知,在 C++ 中,我们不会通过在每个使用它的程序中构建其源文件来使用库——除非它是一个仅头文件的库。一个库本身被构建到一个对象库(静态或动态)中,使用它的程序只需包含库的头文件并链接对象库。
这也是程序应该如何使用您的 Gizmo 库的方式。所以到最后的近似值:-
- 创建一个
libgizmo
构建 Gizmo 对象库的项目(静态或动态,如您所见)。
- 像上面那样做一个项目
gizmo_test
,只是不是编译链接[gizmo_0.cpp,...gizmo_N.cpp]
,而是链接libgizmo
,并使这个项目依赖于libgizmo
项目。
my_prog
像现在一样创建一个项目,而不是编译和链接[gizmo_0.cpp,...gizmo_N.cpp]
,只需链接libgizmo
,并使该项目依赖于该gizmo_test
项目。
因此,当您构建第一个使用 Gizmo 库的程序时,您已经拥有了三个项目。使用 Gizmo 库的每个后续程序都需要一个项目,例如my_prog
项目。
Googletest 是为测试 C++库而设计的,这就是你应该使用它的方式。
现在我对您的程序或您当前如何在项目中部署 Googletest 测试用例一无所知。也许这些测试用例中没有任何定义明确的 API 实现,您可以将其分解为独立库。这可能是因为您的程序非常简单,以至于无法对其“组件”进行单元测试,而您最好只编写程序的黑盒测试。更有可能是因为您迄今为止未能设计出能够进行单元测试的程序架构。如果这是您发现的,则需要修复它,然后以正确的方式应用 Googletest。这将是值得的。
并且如果需要指出,单元测试不是程序测试,以及对您的程序所依赖的任何库进行单元测试,如果它们是您的责任,您还需要对程序进行黑盒测试。