如何在使用单个测试项目时将所有QtTestLib单元测试结果组合在一个文件中?

时间:2012-03-30 14:03:21

标签: c++ qt qtestlib qttest

在我们的项目中,我们使用QtTestLib进行单元测试。原因是整个项目已经尽可能使用Qt并且它是一个GUI应用程序,因此我们希望能够测试GUI界面。

我们的项目由MSVC编译,因此我们不希望每个测试都有一个单独的项目文件,因为它会使解决方案混乱。因此,我们为所有测试创建了一个项目。所有测试都应该在CIS上自动进行(持续集成),因此我们尝试使用一些XSLT转换通过XML格式的输出文件将测试插入Hudson。

但似乎测试输出存在问题。如果对所有测试使用单个main(),并且只为每个测试传输cmd行参数:

#include "MyFirstTest.h"
#include "MySecondTest.h"

int main(int argc, char **argv)
{
  int result = 0;
  MyFirstTest test1;
  result |= QTest::qExec(&test1, argc, argv);
  MySecondTest test2;
  result |= QTest::qExec(&test2, argc, argv);
  return result;
}

然后您将获得多次重写的结果文件。因此,如果您想使用输出文件(例如xml)稍微自动化它,您将只获得其中的最后一个结果。所有其他都将被覆盖。

我们已经尝试过这种方法,它不能让你使用像Hudson这样的持续集成系统。所以我的问题是:有没有机会在一个输出文件中附加结果?当然,我们可以使用一些解决方法,例如通过QTest :: qExec()运行每个测试并使用修改后的参数将结果写入单独的文件,但这似乎不是最好的方法。理想情况下,我希望有一个结果文件与CIS一起使用。

4 个答案:

答案 0 :(得分:4)

通过这个技巧,您可以将各个测试xml报告收集到临时缓冲区/文件中;全部来自单个测试二进制文件。让我们使用QProcess从一个二进制文件中收集单独的测试输出;测试使用修改后的参数调用自身。首先,我们引入一个特殊的命令行参数,它可以正确地利用子测试 - 所有这些都仍在测试可执行文件中。为方便起见,我们使用了接受QStringList的重载qExec函数。然后我们可以更容易地插入/删除我们的“-subtest”参数。

// Source code of "Test"

int
main( int argc, char** argv )
{
  int result = 0;

  // The trick is to remove that argument before qExec can see it; As qExec could be
  // picky about an unknown argument, we have to filter the helper 
  // argument (below called -subtest) from argc/argc; 

  QStringList args;

  for( int i=0; i < argc; i++ )
  {
     args << argv[i];
  }

  // Only call tests when -subtest argument is given; that will usually
  // only happen through callSubtestAndStoreStdout

  // find and filter our -subtest argument

  size_t pos = args.indexOf( "-subtest" );

  QString subtestName;

  if( (-1 != pos) && (pos + 1 < args.length()) )
  {
    subtestName = args.at( pos+1 );

    // remove our special arg, as qExec likely confuses them with test methods

    args.removeAt( pos );
    args.removeAt( pos );

    if( subtestName == "test1" )
    {
      MyFirstTest test1;
      result |= QTest::qExec(&test1, args);
    }

    if( subtestName == "test2" )
    {
      MySecondTest test2;
      result |= QTest::qExec(&test2, args);
    }

    return result;
}

在脚本/命令行调用中:

./Test -subtest test1 -xml ... >test1.xml
./Test -subtest test2 -xml ... >test2.xml

在这里 - 我们有办法分开测试输出。现在我们可以继续使用QProcess'es为您收集标准输出。只需将这些线附加到您的主要部分即可。我的想法是再次调用我们的可执行文件,如果没有请求显式测试,但我们的特殊参数是:

bool
callSubtestAndStoreStdout(const String& subtestId, const String& fileNameTestXml, QStringList args)
{
   QProcess proc;

   args.pop_front();

   args.push_front( subtestId );
   args.push_front( "-subtest" );

   proc.setStandardOutputFile( fileNameTestXml );

   proc.start( "./Test", args );

   return proc.waitForFinished( 30000 ); // int msecs
}

int 
main( int argc, char** argv )
{
   .. copy code from main in box above..

   callSubtestAndStoreStdout("test1", "test1.xml", args);
   callSubtestAndStoreStdout("test2", "test2.xml", args);

   // ie. insert your code here to join the xml files to a single report

   return result;
}

然后在你的脚本/命令行中调用:

./Test -xml           # will generate test1.xml, test2.xml

事实上,希望未来的QTestLib版本可以让您更轻松。

答案 1 :(得分:3)

我使用过这种肮脏的解决方法(适用于Jenkins):

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    int result = 0;
    freopen("MyAppTests_Test1.xml", "w", stdout);
    result |= QTest::qExec(new Test1, argc, argv);
    freopen("MyAppTests_Test2.xml",  "w", stdout);
    result |= QTest::qExec(new Test2, argc, argv);
    return result;
}

然后在Jenkins中我添加了构建操作“执行shell”: ./ path_to_MyAppTests -xml

并添加了Post-build Actions“发布xUnit测试结果报告”(QTestlib)。 QTestlib模式: MyAppTests * .xml

答案 2 :(得分:2)

由于我还没有在这里发表评论,我将在此发布,以补充muenalan的答案。 很少有必须应用它来修复它(至少使用Qt5):

  1. callSubtestAndStoreStdout 有3个错误。首先,在推送新的arg之前,必须从前面弹出第一个arg(这是arg 0)。其次,您必须在开始流程之前重定向输出。第三,它必须返回一些值;)

    if ((-1 != pos) && (pos + 1 < args.length()))
    
  2. 主要还有一些(明显的)错误。主要的是在 if 语句中:

    {{1}}
  3. 因为原来永远不会开火。

    无论如何,感谢解决方案,它解决了我的头痛问题:)

答案 3 :(得分:1)

在我看来,尝试构建一个可执行文件在这里是一个坏主意:如果你的一个测试崩溃,其他测试不再执行......

运行具有多个测试用例的套件的另一种方法:

  • 在顶层创建一个子项目。
  • 为每个测试用例添加一个带有自己的.pro的子文件夹,并将其添加到子项目中。
  • 从顶级文件夹
  • 构建项目
  • 在顶级makefile上运行make check。这将调用所有测试用例。您也可以传递参数,例如在您的MSVC环境中使用nmake -k check TESTARGS="-o result.xml,xml -v2 -maxwarnings 0"。如果一个测试失败,-k开关有助于继续。
  • xunit Jenkins插件作为示例允许像my_build\*\result.xml这样的模式搜索您的xml文件,这样您就可以解析所有生成的文件而无需合并到单个文件。