如何使用Google Test测试EXE?

时间:2014-04-15 15:33:06

标签: c++ googletest

我在Visual Studio中有一个C ++项目,并且已经添加了另一个专门用于测试的项目。这两个项目都是EXE(控制台应用程序)。那么如何在第二个项目中使用第一个项目?

只是为了澄清一下,如果第一个项目是一个可以简单地包含在第二个项目中的图书馆,那么这里的问题将是不言而喻的,但作为一个EXE,这就是问题所在。

6 个答案:

答案 0 :(得分:33)

根据您的意见,您有一个C ++控制台应用程序(MyApp),您已经开发了一些特定于应用程序的类,您希望使用googletest进行单元测试 视觉工作室。怎么样?

正如你所说,如果你想对进行单元测试,那么它的方法就是 明显。你会:

  • 1)创建一个项目来创建单元测试应用程序(UnitTest)。
  • 2)配置include-search目录,以便编译器可以找到库的头文件。
  • 3)配置库搜索目录,以便链接器可以找到库本身。
  • 4)将库本身添加到链接器输入。
  • 5)使UnitTest项目依赖于库项目,以便构建UnitTest以确保MyApp是最新的。
  • 6)根据googletest docs 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}的库搜索目录(以相对或绝对形式)。

    < / LI>

实际上,对于选项b),.obj中很可能有MyAppUnitTest个文件,您必须在UnitTest中进行链接,很有可能它们的数量会增长随着时间的推移。维持{{1}}的正确联系可能会成为一件苦差事,你可能会得出结论,即军官是正确的。

答案 1 :(得分:10)

取决于。 Google Test(主要)是一个单元测试框架(过度简化,测试类)。你可以绝对使用is进行其他类型的测试,但它没有&#34;内置&#34;其他类型测试的功能,您必须自己编写。

如果您尝试对可执行文件进行系统测试,则可以运行该过程。如果您使用的是多平台系统或已经具有提升依赖性,我建议使用Boost.Process。另外,请看这里:launch an exe/process with stdin stdout and stderr?

&#34;测试&#34;你写的将调用可执行文件,并可以相应地输入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对象不会因测试代码而膨胀。

两个要点是:

  • 使用此方法,测试代码仍然与应用程序代码分开组织,但它仍然驻留在同一个Visual Studio项目中,这可能有用也可能没有用。我个人不喜欢管理/担心第二个项目。
  • 像Mike Kinghan所说,自己管理和链接.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命令行中。