6

我有一个关于 Eclipse 中的Googletest的基本问题。

我正在使用test-runner插件来运行 Googletests。但是我需要指定一个运行我的单元测试的二进制文件(当然这是有道理的。)

问题是在我的项目中,我现在有两个主要功能,一个是运行实际程序,一个是

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

运行谷歌测试。

每次我想运行一个时,我都会将另一个注释掉,这当然是愚蠢的。

但是你用什么练习来处理这种情况?

4

2 回答 2

3

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。这将是值得的。

并且如果需要指出,单元测试不是程序测试,以及对您的程序所依赖的任何库进行单元测试,如果它们是您的责任,您需要对程序进行黑盒测试。

于 2015-07-11T09:28:23.660 回答
0

确实是一个有效的问题。我相信 Mike Kinghan 的详细回复解释了您应该如何使用 google-test,但没有什么是一成不变的,最后,您可以以任何您想要的方式使用 google-test。

所以,既然我真的遇到了类似的情况,我做的就比较简单了。

我修改了生产文件源代码,以便主要功能将从此更改:

void main(void)

对此:

#ifndef TDD_ENABLED // TDD_ENABLED is defined only in the unit test project
    void main(void)
#else
    void main_app(void)
#endif

这样,当您运行单元测试时,原始的“main”函数将转换为“main_app”,您可以避免与谷歌测试的“main”发生冲突。当您运行原始生产代码项目时,“main_app”函数应再次命名为“main”。因此,从技术上讲,从您的生产代码的角度来看,没有任何改变。

于 2021-01-25T12:56:50.413 回答