Как собрать результаты всех модульных тестов QtTestLib в один файл при использовании одного тестового проекта? - PullRequest
5 голосов
/ 30 марта 2012

В нашем проекте мы используем QtTestLib для модульного тестирования. Причины в том, что весь проект уже использует Qt, когда это возможно, и это приложение с графическим интерфейсом, поэтому мы хотели иметь возможность тестировать интерфейсы графического интерфейса.

Наш проект скомпилирован MSVC, поэтому мы не хотели иметь отдельный файл проекта для каждого теста, потому что это будет загромождать решение. Таким образом, мы создали единый проект для всех тестов. Все тестирование должно быть автоматизировано в CIS (непрерывная интеграция), поэтому мы попытались подключить наши тесты к Hudson через выходной файл в формате XML, используя некоторые преобразования XSLT.

Но, похоже, проблема с выводом тестов. Если вы используете один 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 ]

4 голосов
/ 16 апреля 2012

С помощью этого трюка вы можете собирать отдельные тестовые отчеты xml во временные буферы / файлы; все из одного тестового двоичного файла. Позволяет использовать QProcess для сбора отдельных результатов теста из одного двоичного файла; тест вызывает себя с измененными аргументами. Во-первых, мы вводим специальный аргумент командной строки, который использует правильные подтесты - все это все еще в вашем тестовом исполняемом файле. Для нашего удобства мы используем перегруженную функцию qExec, которая принимает QStringList. Затем мы можем легче вставить / удалить наш аргумент "-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 для сбора stdout для вас. Просто добавьте эти строки в свою главную. Идея состоит в том, чтобы снова вызвать наш исполняемый файл, если не требуется никаких явных тестов, но с нашим специальным аргументом:

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 облегчат эту задачу.

3 голосов
/ 21 марта 2014

Я использовал этот грязный обходной путь (работает с Дженкинсом):

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 я добавил действие сборки "execute shell": . / Path_to_MyAppTests -xml

и добавлены Действия после сборки "опубликовать отчет о результатах теста xUnit" (QTestlib). Шаблон QTestlib: MyAppTests * .xml

2 голосов
/ 03 ноября 2015

Поскольку я пока не могу комментировать, я опубликую это здесь в дополнении к ответу Муеналана. Есть несколько исправлений, которые нужно применить для его работы (по крайней мере, с Qt5):

  1. callSubtestAndStoreStdout содержит 3 ошибки. Во-первых, первый аргумент должен быть извлечен спереди (это аргумент 0), прежде чем выдвигать новые. Во-вторых, вы должны перенаправить вывод до запуска процесса. В-третьих, он должен вернуть какое-то значение;)

    QProcess proc;
    args.pop_front();
    args.push_front(subtestId);
    args.push_front("-subtest");
    
    proc.setStandardOutputFile(fileNameTestXml);
    proc.start("sportSystemTest.exe", args);
    return proc.waitForFinished(30000);
    
  2. main также имеет некоторые (очевидные) ошибки. Основной из них в выражении if :

    if ((-1 != pos) && (pos + 1 < args.length()))
    

как оригинал никогда не будет стрелять.

В любом случае, спасибо за решение, оно решило мою большую головную боль:)

1 голос
/ 09 февраля 2018

На мой взгляд, попытка создать один исполняемый файл - плохая идея: если один из ваших тестов завершится с ошибкой, другие больше не будут выполняться ...

Другой способ запустить набор с несколькими тестовыми сценариями:

  • Создание проекта subdirs на верхнем уровне.
  • добавьте подпапку с собственным .pro для каждого теста и добавьте это в проект subdirs.
  • построить проект из папки верхнего уровня
  • запустите make check на make-файле верхнего уровня. Это вызовет все ваши тестовые случаи. Вы также можете передать параметры, например, используйте nmake -k check TESTARGS="-o result.xml,xml -v2 -maxwarnings 0" с вашей средой MSVC. Ключ -k помогает продолжить работу, если один тест не пройден.
  • Плагин xunit Jenkins в качестве примера позволяет шаблону, подобному my_build\*\result.xml, искать ваши XML-файлы, и таким образом вы можете анализировать все сгенерированные файлы без объединения в один файл.
...