我在Visual Studio中有一个C ++项目,并且已经添加了另一个专门用于测试的项目。这两个项目都是EXE(控制台应用程序)。那么如何在第二个项目中使用第一个项目?
只是为了澄清一下,如果第一个项目是一个可以简单地包含在第二个项目中的图书馆,那么这里的问题将是不言而喻的,但作为一个EXE,这就是问题所在。
答案 0 :(得分:33)
根据您的意见,您有一个C ++控制台应用程序(MyApp)
,您已经开发了一些特定于应用程序的类,您希望使用googletest进行单元测试
视觉工作室。怎么样?
正如你所说,如果你想对库进行单元测试,那么它的方法就是 明显。你会:
UnitTest
)。 UnitTest
项目依赖于库项目,以便构建UnitTest
以确保MyApp
是最新的。UnitTest
app编码。但是,由于您要进行单元测试的课程特定于MyApp
,因此您没有。{
库。
一个训练军士的回答是:你没有一个包含你要进行单元测试的类的库?所以制作一个!
这样你就可以使用3个项目: -
MyAppLib
,生成包含您要进行单元测试的所有功能的库。MyApp
,生成与目前相同的可执行文件,但链接MyAppLib
UnitTest
,生成可执行单元测试MyAppLib
,也链接MyAppLib
但是如果你不喜欢训练中士的答案,你可以解决它。
从通常的构建系统角度(设计到Visual Studio中的那个),
MyApp
项目的重要输出是构建目标 - .exe
。
生成的.obj
个文件只是中间副产品。 VS不为您提供支持
用于将这些副产品视为依赖项目的自动链接器输入,并且如果依赖项目也是同一类型的.exe
- 就像您的情况那样 - 那么无论如何这样的自动链接都是不可能的,因为主要的入口点将被多重定义。
但从单元测试的角度来看,情况恰恰相反。 .exe
没有意义,而(某些).obj
文件全部或部分包含您要进行单元测试的类的实现。在foo
中定义了foo.h
类并在foo.cpp
中实现的文本书案例中,foo.obj
的链接中需要对象文件UnitTest
。
为简单起见,假设MyApp
仅使用一个特定于应用程序的类foo
,
在foo.h
中定义并在foo.cpp
中实施。然后,您有两个选项来构建UnitTest
。
a)您可以将foo.cpp
添加到UnitTest
的源文件中。当然不要复制它。只需从MyApp
的源文件夹添加现有项。然后你就完成了,但是这个
当然还有一个缺点,即foo.cpp
在内部进行了不适当的编辑
UnitTest
项目。
b)您可以将foo.obj
视为UnitTest
链接所需的静态库,并按照上述步骤1) - 6)进行处理。这尤其意味着在步骤3)UnitTest
的{Debug | Release}版本配置了包含\path\to\MyApp\{Debug|Release}
的库搜索目录(以相对或绝对形式)。
实际上,对于选项b),.obj
中很可能有MyApp
个UnitTest
个文件,您必须在UnitTest
中进行链接,很有可能它们的数量会增长随着时间的推移。维持{{1}}的正确联系可能会成为一件苦差事,你可能会得出结论,即军官是正确的。
答案 1 :(得分:10)
取决于。 Google Test(主要)是一个单元测试框架(过度简化,测试类)。你可以绝对使用is进行其他类型的测试,但它没有"内置"其他类型测试的功能,您必须自己编写。
如果您尝试对可执行文件进行系统测试,则可以运行该过程。如果您使用的是多平台系统或已经具有提升依赖性,我建议使用Boost.Process。另外,请看这里:launch an exe/process with stdin stdout and stderr?
"测试"你写的将调用可执行文件,并可以相应地输入stdin或stdout。
例如:
std::string path_to_exectuable = "thepath";
TEST(FooTester,CheckHelpScriptReturns0)
{
using bp =::boost::process;
std::vector<std::string> args; args.push_back("--help");
bp::context ctx;
ctx.stdout_behavior = bp::capture_stream();
bp::child c = bp::launch(exec, args, ctx);
bp::status s = c.wait();
ASSERT_TRUE(s.exited())<<"process didn't exit!";
ASSERT_EQ(s.exit_status(),0)<<"Help didn't return 0";
}
答案 2 :(得分:3)
我处于类似的情况,我设置的方式有效地完成了Mike Kinghan的答案,就编译器而言,但与用户的方式不同#&# 39;观点。
我所做的是创建一个我称之为#34; Testing&#34;的自定义配置。您可以通过打开项目设置,选择&#34; Configuration Manager ...&#34;来创建新配置。并选择&#34;新...&#34;在配置选择框中。
出现提示时,我选择复制默认设置&#34; Debug&#34;配置,以便我可以使用我的测试调试器,就像我在&#34; Debug&#34;配置。
在新的测试配置下,我像往常一样为编译器和链接器设置选项以使用谷歌测试。
属性的重要变化是我定义了一个预处理器变量,我将其称为&#34; TESTING&#34;。
我改写了我的&#34; main.cpp&#34;看起来像这样:
...
// includes
// functions
// whatever
...
#ifdef TESTING
#include <gtest/gtest.h>
#endif
int main(int argc, char **argv) {
#ifdef TESTING
::testing::InitGoogleTest(&argc, argv);
int val = RUN_ALL_TESTS();
getchar(); // not necessary, but keeps the console open
return val;
#endif
// rest of main() as normal...
}
我想要表明的是,我只在main
定义的地方改变了几行,我不必在整个文件中进行重大更改。
现在这一切都已设置完毕,我只是为我的测试创建了一个新的源文件夹,并创建了&#34; .cpp&#34;那里的文件。为了避免膨胀正常的可执行文件,我用检查TESTING变量来包装这些文件,所以我有这样的东西:
tests/Test.cpp:
#ifdef TESTING
#include <gtest/gtest.h>
#include "my_class_header.h"
TEST(TestMyClass, test_something) {
// perform some test on class
}
#endif
我认为这些文件仍然会被点击&#34;由编译器在Debug和Release配置下,因此有大量这些可能会减慢构建速度,但Debug和Release对象不会因测试代码而膨胀。
两个要点是:
.obj
文件可能会成为一件苦差事,但通过使用此方法,默认的Visual Studio设置可以为您管理。一个缺点是所有目标文件的有效冗余副本将在&#34;测试&#34;输出目录。有了更多的配置,肯定必须有一种方式来分享&#34;调试对象文件,但我没有理由去那么远。
这是一个非常简单的方法,可能比将应用程序重构为单独的库和主要方法容易得多。我不喜欢爱使用预处理器wankery,但在这种情况下,它相当简单,没有太多的代码膨胀,并完全满足它所需要的。您可以始终以另一种方式触发测试,而无需使用预处理器。
答案 3 :(得分:0)
如果要测试控制台应用程序,可以运行测试,打开控制台窗口并运行第一个应用程序的exe文件。 然后在你的googletest中捕获你刚刚运行的exe的标准输出。
[为了更好地控制第一个应用程序,您可能需要将第一个应用程序解析参数发送给它,例如一些标志,如-x或你需要的东西。]
答案 4 :(得分:0)
我准备了一个github repo,其中包括Mike Studio&#34; drill-sergeant&#34;中的Visual Studio 2015解决方案。建议。您可以直接使用它,无需任何额外要求或依赖。
https://github.com/fuatcoskun/GoogleTestVS2015
我希望它有所帮助...
答案 5 :(得分:0)
如果您对在不同项目中进行测试不是很严格,可以在应用程序项目中编写测试。然后让应用程序在接收某些命令行参数时执行测试,否则执行正常的应用程序逻辑,即
int main(int argc, char* argv[])
{
if (argc >= 2 && std::string(argv[1]) == "--tests")
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
else
{
// Application logic goes here
}
}
TEST(ExampleTests, TestSQRTCalculation) // assuming all the right headers are included
{
EXPECT_NEAR(2.0, std::sqrt(4.0), 0.000001);
}
这样可以避免为了测试的目的而创建一个不必要的库,尽管如果它在结构上是正确的,你仍然可以这样做。缺点是测试代码会进入您要发布的可执行文件。如果你不想要,我猜你需要一个额外的配置来指定一个禁用测试的预处理器指令。
调试测试或在后期构建时自动运行它们很简单,只需将“--tests”指定为debug args或分别在post build命令行中。