连接器错误 - 链接两个“应用程序”类型的项目以使用Google Test。

7
我正在尝试使用Google Test测试一个函数。
似乎一切都设置正确,如果没有gtest,它可以正常构建和执行...(由于代码有些复杂,所以我无法在此列出所有源文件,但是没有添加gtest,文件链接正常,并按照预期运行)。
这是一个应用程序类型的项目。它具有多个库依赖项...不相关。
测试项目作为单独的项目添加到解决方案中。它将被测试的项目作为依赖项。测试项目的.h文件仅指向gtest... .cpp(不是标准的InitGoogleTest main)添加了自己的头文件,被测试项目的头文件,并且具有下面显示的测试。
当项目构建时,会自动创建TestedProject.lib,即使它是一个应用程序。我已将TestedProject.lib作为库依赖项添加到TestProject中(在Link中)。
Class x
{
public:
  x(){}    // I didn't really need this, I only added the class so I have access to 
  ~x(){};  // non-class methods with gtest - but it still doesn't work
  bool myFunction(std::string a, double b, bool c);  
};

实现:

bool x::myFunction(std::string a, double b, bool c)
{
  // implementation
  return false;
}

somewhere_else
{
  x x_instance;
  y = x_instance.myFunction("a", 1, false);   // works, all builds, executes, life is great
}

添加单元测试:

class TheTest : public ::testing::Test
{
protected:
    x x_instance;
};

TEST_F(TheTest, Fail)
{
    EXPECT_FALSE(x_instance.myFunction("a", 1, false));     
}

无法编译。链接错误(已修改,类似上面的示例代码,使用简化名称,希望我没有搞砸内容)。

Error   2   error LNK2019: unresolved external symbol 
"public: bool __thiscall x::myFunction(class std::basic_string<char,struct std::char_traits<char>,double,bool)" 
(?myFunction@x@@QAE_NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@00000NNNN_N1@Z) 
referenced in function "private: virtual void __thiscall TheTest_Fail_Test::TestBody(void)" 
(?TestBody@TheTest_Fail_Test@@EAEXXZ)   C:\path\file.obj

我以前做过这个 - 解决链接错误并使用Google测试编写了一些测试 - 但我看不出有什么问题。

作为一个测试,我在头文件中写了一小段代码:

int test(){return 4;}

然后,用以下代码替换test:

EXPECT_EQ(x.test(), 4);

它可以正常工作。太好了。但这意味着必须将所有测试的代码放在一个单独的文件中,如cpp文件之类的,这是不合理的。这个应用程序项目中有几个文件。

我该怎么解决这个问题?我该如何让Google Test链接和测试具有头文件和实现文件的类?当这个头文件/实现在不同的"应用程序"类型的项目中时?

到目前为止,我找到的唯一相似的问题:C++链接问题 - 当跨链接同一解决方案中的不同项目时

请帮我找到解决方案。


通常情况下,您会有一个库(或一些库)组成您自己的代码大部分,并且有一个仅包含“main”函数的exe /应用程序,该函数链接您的lib(s)。这样,您可以拥有另一个具有不同“main”的项目和一堆测试代码(如果需要,可以在多个文件中),这些代码链接您的lib(s)。您不应该期望能够链接具有2个“main”的2个应用程序。 - Fraser
谢谢。我就是这样实现的,当我结束提问后,我发现了一个帮助我解决问题的链接,于是我立即开始实施。我不得不创建一个独立的项目,并提取一个很小的main()方法放进去。我原本期望能够将两个带有main()的应用程序进行链接...但我花了很长时间才弄清楚我不能这样做。我相信总会有一个“链接错误手册”,或者“可以测试的手册”,或者“其他人已经尝试过并失败的事情,所以要避免犯同样的错误”的手册...我想阅读它。 - Thalia
是啊 - 我也是!编译器错误通常比链接器错误容易解决。 - Fraser
3个回答

10

还有另一种解决方案,我更喜欢它,因为这意味着您可以避免更改主项目:

在主项目中添加“后构建操作”,以便为完全相同的源文件创建静态库。 然后,您只需将此依赖项添加到gtest项目中即可。

每次编译主项目时,它都会构建应用程序和静态库。

这样,您就不必创建第三个项目并保持配置同步。

希望对您有所帮助。


7
具体的设置应该是:打开主项目属性,选择构建事件->后期构建事件选项卡。使用命令*lib /NOLOGO /OUT:"$(TargetPath).lib" "$(ProjectDir)$(Configuration)*.obj"*,这样将生成一个$(ProjectName).exe.lib文件和.exe文件一起,对于静态链接到单元测试项目非常有用。 - yc2986
这个答案应该被接受为最佳答案。@yc2986的评论也有所帮助。但是对于我的情况,我需要稍微修改建议的命令:lib /NOLOGO /OUT:"$(TargetPath).lib" "$(ProjectDir)obj$(Configuration)$(PlatformTarget)*.obj" - Yurii S
2
在两个平台上构建.lib文件的正确命令是:lib /NOLOGO /OUT:"$(TargetPath).lib" "$(ProjectDir)$(IntDir)*.obj"。请使用$(IntDir) - KulaGGin
1/2 还有,C++ 真的太尴尬了。> 开始阅读 Kent Beck 所写的《测试驱动开发》。> 对 Python 和 Java 以及 IntelliJ IDE 没有任何先前的知识。下载 IntelliJ IDEA,在几个小时内因为糟糕的文章(https://www.jetbrains.com/help/idea/testing.html#create-test-resources-root)设置测试框架中的怪癖。> 没有遇到任何问题地跟随书中的第一章。> 下载并设置 IntelliJ PyCharm。> 在几分钟内设置测试框架。> 没有遇到任何问题地跟随书中的第二和第三章直到最后一页。 - KulaGGin
我可以建议您在回答中明确指出,应该从静态库中删除main对象,以避免对libgtest_main的链接器覆盖吗?请参见@Radek在这一点上的有用答案。 - Zilog80
显示剩余3条评论

2

那么我将给出答案:

对于我的问题,我有2种解决方案:

1)将应用程序项目拆分为2个项目,一个将成为库,包含大部分代码;另一个将是应用程序,包含一个调用真实代码入口点(如参数解析方法或其他方法)的小型main()。

然后,我可以添加单元测试项目 - 以测试库。

2)不要拆分项目。 添加gtest项目,不创建任何依赖项。 将要测试的文件添加到gtest项目中。 gtest项目将是一个独立的可执行文件... 满足所有需要。(优点:无需依赖项进行测试)

我更喜欢第一种版本。


0

这个问题还有另一个解决方案。

只需为Google Test Framework创建一个新项目。 (当然,在您现有的应用程序解决方案下)。

然后,在确保所有Google Test Framework设置正确之后。 (可以在新创建的解决方案中测试它)

手动将您要测试的代码(使用“添加”->“现有项”)从主项目中包含进来,然后您就可以在不生成额外库的情况下测试您的代码了。

这样做的好处是,当您测试某些需要来自Windows的DLL的应用程序时,它需要应用程序使用多线程调试DLL。 (在项目属性设置中,转到C/C++ -> 代码生成 - > 运行时库查看您得到的内容)

而Google Test Framework使用非常不同的运行时库(多线程调试(/MTd))。

在链接阶段,编译器将报告它在链接生成的lib时遇到了一些困难,因为您的应用程序和Google框架的lib都是多线程的。

通过这种方式,您可以避免两个项目的依赖问题。(一个为/Mtd,另一个为/Md)


你的解决方案与我5年前发布的第二个选项完全相同。 - Thalia
没有伤害把这个解释得更长些 - ycomp
最好有一个更长的解释,这样也不会有什么影响。 - ycomp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接