gpt4 book ai didi

googletest - GTest无法在单独的编译单元中找到测试

转载 作者:行者123 更新时间:2023-12-03 21:55:22 27 4
gpt4 key购买 nike

我有一个用C ++编写的程序,其中一些子文件夹包含链接的库。有一个顶级SConscript,它在子文件夹/库中调用SConscript文件。

在库cpp中,有一个GTest:

TEST(X, just_a_passing_test) {
EXPECT_EQ(true, true);
}


顶层程序源中有main(),它仅调用GTests main,并具有另一个GTest:

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

TEST(Dummy, should_pass){
EXPECT_EQ(true, true);
}


现在的问题是,当我运行程序时,GTest仅在main.cpp源代码中运行测试。忽略库中的测试。现在,当我以无副作用的方式(例如“ SomeClass foo;”)在main.cpp中的同一库cpp中引用一个不相关的类时,该测试就变​​得异常奇怪。我试过使用-O0和其他技巧来强制gcc不优化未调用的代码。我什至尝试过Clang。
我怀疑这与GTest在编译过程中如何测试发现有关,但是我找不到有关此问题的任何信息。我相信它使用静态初始化,因此可能存在一些奇怪的排序。
任何帮助/信息将不胜感激!

更新:尽管它专门针对Visual C ++,但在FAQ中找到了一个听起来像此问题的部分。其中包括一个技巧/技巧,可以强制编译器在未引用的情况下不丢弃该库。
它建议不要在库中进行测试,但这让我想知道在没有每个库都具有可执行文件的情况下,如何测试库又会导致快速运行它们并产生肿的输出。
https://code.google.com/p/googletest/wiki/Primer#Important_note_for_Visual_C++_users

最佳答案

从场景设置中收集了其gtest测试用例的库
丢失是在应用程序构建中静态链接的。还有那个
GNU工具链正在使用中。

问题行为的原因很简单。考试
程序不包含对库中任何内容的引用
TEST(X, just_a_passing_test)。因此,链接器不需要链接任何链接
该库中的目标文件来链接程序。事实并非如此。所以
gtest运行时在可执行文件中找不到该测试,因为它不存在。

有助于理解GNU格式的静态库是存档
对象文件,并用一个管家标题块和一个全局符号表装饰。

OP通过在程序中编码一个临时引用来发现
问题库中的任何公共符号,他都可以“神奇地”强迫它
测试用例进入程序。

没魔术为了满足对该公共符号的引用,链接器为
现在必须从库中链接一个目标文件-该文件包含
符号的定义。而OP则表示图书馆是由
来自.cpp。因此,库中只有一个目标文件,
也包含测试用例的定义。在目标文件中
链接,测试用例在程序中。

OP徒劳地使用了编译器选项,从GCC切换到clang,
寻找实现同一目标的更受人尊敬的方式。编译器是
不相关的。 GCC或clang,它由系统链接器ld完成链接
(除非已采取非常规措施替换它)。

是否有一种更受人尊敬的方式让ld链接来自
静态库,即使程序未在该目标文件中引用任何符号?

有。说问题程序是app,问题静态库是
libcool.a

然后,链接app的常规GCC命令行类似于
要点:

g++ -o app -L/path/to/the/libcool/archive -lcool


这会将命令行委托给 ld,并带有其他链接器选项和
g++认为是所在系统的默认库。

当链接程序考虑使用 -lcool时,它将确定这是一个请求
对于档案 /path/to/the/libcool/archive/libcool.a。然后它将图
在这一点上是否仍然有未解决的符号引用
其定义被编译在 libcool.a中的目标文件中。如果有
任何,那么它将把那些目标文件链接到 app。如果没有,那么它链接
libcool.a中没有任何内容,然后继续。

但是我们知道 libcool.a中有一些我们想要的符号定义
链接,即使 app没有引用它们。在这种情况下,我们可以知道
链接器从 libcool.a链接目标文件,即使它们是
未引用。更准确地说,我们可以告诉 g++告诉链接器执行此操作,
像这样:

g++ -o app -L/path/to/the/libcool/archive -Wl,--whole-archive -lcool -Wl,-no-whole-archive


这些 -Wl,...选项告诉 g++将选项 ...传递给 ld--whole-archive
选项告诉 ld链接后续归档中的所有目标文件,无论它们是否
是否引用,直到另行通知。 -no-whole-archive告诉
ld停止这样做,并照常营业。

看起来 -Wl,-no-whole-archive是多余的,因为它是
g++命令行。但事实并非如此。请记住, g++会附加系统默认库
传递到 ld之前,先在幕后转到命令行。你一定是
链接这些默认库时,不希望 --whole-archive生效。
(链接将因多个定义错误而失败)。

将此解决方案应用于问题案例和 TEST(X, just_a_passing_test)
将被执行,而不会强迫程序进行一些不操作
引用到定义该测试的目标文件中。

在一般情况下,此解决方案存在明显的缺点。如果发生这种情况,该库来自
我们要强制链接一些未引用的目标文件,其中包含一个
一堆我们真正不需要的其他未引用对象文件。
--whole-archive也将它们链接在一起,它们只是程序中的膨胀。

--whole-archive解决方案可能比无操作引用更受人尊敬
骇客,但这并不值得尊重。它甚至看起来都不值得尊重。

真正的解决方案是做合理的事情。如果你想要
链接程序链接程序中某些内容的定义,然后不要将其保密
链接器。至少在您所在的每个编译单元中声明该事物
期望使用其定义。

gtest测试用例做合理的事情需要理解
gtest这样的 TEST(X, just_a_passing_test)宏扩展为类定义,
在这种情况下:

class X_just_a_passing_test_Test : public ::testing::Test {
public:
X_just_a_passing_test_Test() {}
private:
virtual void TestBody();
static ::testing::TestInfo* const test_info_ __attribute__ ((unused));
X_just_a_passing_test_Test(X_just_a_passing_test_Test const &);
void operator=(X_just_a_passing_test_Test const &);
};


(加上 test_info_的静态初始化程序和 TestBody()的定义)。

对于 TEST_FTEST_P变体也是如此。因此,您可以部署这些
您代码中的宏具有与约束相同的约束和期望
适用于类定义。

因此,如果您有在 libcool中定义的库 cool.h,并在 cool.cpp中实现
并希望 gtest对其进行单元测试,以使其由测试程序 tests执行
tests.cpp中实现的,合理的事情是:


编写头文件 cool_test.h
其中的 #include "cool.h"
#include <gtest/gtest.h>
然后在其中定义您的 libcool测试用例
#include "cool_test.h"中的 tests.cpp
编译并链接 tests.cpplibcoollibgtest


很明显,您为什么不做OP所做的事情。您不会定义
tests.cppcool.cpp所需的类,而 cool.cpp不需要的类
不在 tests.cpp中。

OP反对在库中定义测试用例的建议
因为:


在没有每个可执行文件的情况下,您将如何测试库,
使他们快速奔跑感到痛苦。


根据经验,我建议您维护 gtest可执行文件的做法
每个要进行单元测试的库:使用通用的自动化工具可以快速运行它们
这样的 make,并且每个库获得通过/失败判决的结果要好于
只是一堆图书馆的裁决。但是,如果您不想这样做,那么仍然没有任何东西
异议:

// tests.cpp
#include "cool_test.h"
#include "cooler_test.h"
#include "coolest_test.h"

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


编译并链接到 libcoollibcoolerlibcoolestlibgtest

关于googletest - GTest无法在单独的编译单元中找到测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17912988/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com