Pergunta

Eu estou apenas começando um novo projeto que precisa de algum GUI multi-plataforma, e nós escolhemos Qt como o GUI-quadro.

Precisamos de um quadro de teste de unidade, também. Até cerca de um ano atrás nós usamos um quadro de testes de unidade in-house desenvolvido para C ++ - projetos, mas agora estamos em transição para o uso do Google de teste para novos projetos

.

Alguém tem alguma experiência com o uso do Google Teste para Qt aplicações? QtTest / QTestLib é uma alternativa melhor?

Eu ainda não tenho certeza de quanto nós queremos usar Qt nas partes não-GUI do projeto - nós provavelmente preferem usar apenas STL / impulso no código-core com uma pequena interface para a interface gráfica baseada em Qt .

EDIT: Parece que muitos estão inclinando-se para QtTest. Há alguém que tem alguma experiência com a integração deste com um servidor de integração contínua? Além disso, parece-me que ter que lidar com um aplicativo separado para cada novo caso de teste poderia causar muito atrito. Existe alguma boa maneira de resolver isso? Does Qt Creator tem uma boa maneira de lidar com esses casos de teste ou você precisaria ter um projeto por caso de teste?

Foi útil?

Solução

Eu não sei que QTestLib é "melhor" do que um quadro para o outro em termos gerais. Há uma coisa que ele faz bem, e isso é fornecer uma boa maneira de aplicações baseadas ensaio Qt.

Você poderia integrar QTest em sua configuração nova base Google Teste. Eu não tentei, mas com base em como QTestLib é arquitetado, parece que ele não seria muito complicado.

testes escritos com pura QTestLib tem uma opção -xml que você poderia usar, junto com algumas transformações XSLT para converter para o formato necessário para um servidor de integração contínua. No entanto, um monte de que depende de qual servidor CI ir com você. Eu imagino que o mesmo se aplica a gtest.

Um aplicativo de teste único por caso de teste não causou muita fricção para mim, mas isso depende da existência de um sistema de construção que iria fazer um trabalho decente de gerenciamento da construção e execução dos casos de teste.

Eu não sei de nada em Qt Creator, que exigiria um projeto separado por caso de teste, mas poderia ter mudado desde a última vez que olhei para Qt Creator.

Eu também sugeriria furar com QtCore e ficar longe do STL. Usando QtCore ao longo fará com que lidar com os bits GUI que exigem os tipos de dados do Qt mais fácil. Você não terá que se preocupar sobre a conversão de um tipo de dados para outro, nesse caso.

Outras dicas

Você não tem que criar aplicações testes separados. Basta usar qExec em uma função principal independente (), semelhante a esta:

int main(int argc, char *argv[])
{
    TestClass1 test1;
    QTest::qExec(&test1, argc, argv);

    TestClass2 test2;
    QTest::qExec(&test2, argc, argv);

    // ...

    return 0;
}

Isto irá executar todos os métodos de ensaio em cada classe em um lote.

arquivos Seu testclass .h ficaria da seguinte forma:

class TestClass1 : public QObject
{
Q_OBJECT

private slots:
    void testMethod1();
    // ...
}

Infelizmente esta configuração não é muito bem descrito na documentação do Qt mesmo que parece ser bastante útil para muita gente.

Para anexar a resposta de Joe.

Aqui está um uso I pequena cabeçalho (testrunner.h), que contém uma classe de utilitário gerando um ciclo de eventos (que é, por exemplo, precisava de teste na fila conexões sinal de slots e bancos de dados) e "correr" aulas QTest compatíveis:

#ifndef TESTRUNNER_H
#define TESTRUNNER_H

#include <QList>
#include <QTimer>
#include <QCoreApplication>
#include <QtTest>

class TestRunner: public QObject
{
    Q_OBJECT

public:
    TestRunner()
        : m_overallResult(0)
    {}

    void addTest(QObject * test) {
        test->setParent(this);
        m_tests.append(test);
    }

    bool runTests() {
        int argc =0;
        char * argv[] = {0};
        QCoreApplication app(argc, argv);
        QTimer::singleShot(0, this, SLOT(run()) );
        app.exec();

        return m_overallResult == 0;
    }
private slots:
    void run() {
        doRunTests();
        QCoreApplication::instance()->quit();
    }
private:
    void doRunTests() {
        foreach (QObject * test, m_tests) {
            m_overallResult|= QTest::qExec(test);
        }
    }

    QList<QObject *> m_tests;
    int m_overallResult;
};

#endif // TESTRUNNER_H

Use-o assim:

#include "testrunner.h"
#include "..." // header for your QTest compatible class here

#include <QDebug>

int main() {
    TestRunner testRunner;
    testRunner.addTest(new ...()); //your QTest compatible class here

    qDebug() << "Overall result: " << (testRunner.runTests()?"PASS":"FAIL");

    return 0;
}

Eu comecei usando QtTest para o meu aplicativo e muito, muito rapidamente começou a correr em limitações com ele. Os dois principais problemas foram:

1) Meus testes correr muito rápido - de forma suficientemente rápida que a sobrecarga de carregar um arquivo executável, a criação de um aplicativo Q (Core) (se necessário), etc, muitas vezes supera o tempo de execução dos próprios testes! Ligando cada executável tem um monte de tempo, também.

A sobrecarga não parava de aumentar à medida que mais e mais classes foram adicionados, e logo se tornou um problema - um dos objetivos de testes de unidade devem ter uma rede de segurança que corre tão rápido que ele não é um fardo em tudo, e este foi rapidamente tornando-se não o caso. A solução é glob múltiplos conjuntos de teste para um executável, e ao mesmo tempo (como mostrado acima), este é principalmente capaz de fazer, é não suportado e tem limitações importantes.

2) Sem suporte de fixação -. Um deal-breaker para mim

Então, depois de um tempo, eu mudei para Google Teste - é um quadro muito mais featureful e sofisticados testes de unidade (especialmente quando usado com o Google Mock) e resolve 1) e 2), e, além disso, você ainda pode facilmente usar o calhar QTestLib recursos como QSignalSpy e simulação de eventos de GUI, etc. foi um pouco de dor de switch, mas felizmente o projeto não tinha avançado muito longe e muitas das mudanças poderia ser automatizado.

Pessoalmente, eu não vou estar usando QtTest sobre o Google teste para futuros projetos -. Se não oferece vantagens reais que eu posso ver, e tem desvantagens importantes

Por que não usar o framework de teste de unidade incluída no Qt? Um exemplo:. QtTestLib Tutorial

Eu unidade testada nossas bibliotecas usando gtest e QSignalSpy . Use QSignalSpy para sinais de captura. Você pode chamar ranhuras diretamente (como métodos normais) para testá-los.

QtTest é principalmente útil para testar peças que requerem a / envio de sinal Qt evento loop. Ele foi projetado de uma maneira que cada caso de teste requer um executável separado, por isso não deve conflito com qualquer framework de teste existente utilizado para o resto da aplicação.

(Btw, eu recomendo usar QtCore mesmo para partes não-GUI das aplicações. É muito mais agradável para trabalhar.)

Para estender mlvljr é e solução de Joe podemos até mesmo apoiar opções QtTest completos por uma classe de teste e ainda executar tudo em um lote mais de log:

usage: 
  help:                                        "TestSuite.exe -help"
  run all test classes (with logging):         "TestSuite.exe"
  print all test classes:                      "TestSuite.exe -classes"
  run one test class with QtTest parameters:   "TestSuite.exe testClass [options] [testfunctions[:testdata]]...

Header

#ifndef TESTRUNNER_H
#define TESTRUNNER_H

#include <QList>
#include <QTimer>
#include <QCoreApplication>
#include <QtTest>
#include <QStringBuilder>

/*
Taken from https://stackoverflow.com/questions/1524390/what-unit-testing-framework-should-i-use-for-qt
BEWARE: there are some concerns doing so, see  https://bugreports.qt.io/browse/QTBUG-23067
*/
class TestRunner : public QObject
{
   Q_OBJECT

public:
   TestRunner() : m_overallResult(0) 
   {
      QDir dir;
      if (!dir.exists(mTestLogFolder))
      {
         if (!dir.mkdir(mTestLogFolder))
            qFatal("Cannot create folder %s", mTestLogFolder);
      }
   }

   void addTest(QObject * test)
   {
      test->setParent(this);
      m_tests.append(test);
   }

   bool runTests(int argc, char * argv[]) 
   {
      QCoreApplication app(argc, argv);
      QTimer::singleShot(0, this, SLOT(run()));
      app.exec();

      return m_overallResult == 0;
   }

   private slots:
   void run() 
   {
      doRunTests();
      QCoreApplication::instance()->quit();
   }

private:
   void doRunTests() 
   {
      // BEWARE: we assume either no command line parameters or evaluate first parameter ourselves
      // usage: 
      //    help:                                        "TestSuite.exe -help"
      //    run all test classes (with logging):         "TestSuite.exe"
      //    print all test classes:                      "TestSuite.exe -classes"
      //    run one test class with QtTest parameters:   "TestSuite.exe testClass [options] [testfunctions[:testdata]]...
      if (QCoreApplication::arguments().size() > 1 && QCoreApplication::arguments()[1] == "-help")
      {
         qDebug() << "Usage:";
         qDebug().noquote() << "run all test classes (with logging):\t\t" << qAppName();
         qDebug().noquote() << "print all test classes:\t\t\t\t" << qAppName() << "-classes";
         qDebug().noquote() << "run one test class with QtTest parameters:\t" << qAppName() << "testClass [options][testfunctions[:testdata]]...";
         qDebug().noquote() << "get more help for running one test class:\t" << qAppName() << "testClass -help";
         exit(0);
      }

      foreach(QObject * test, m_tests)
      {
         QStringList arguments;
         QString testName = test->metaObject()->className();

         if (QCoreApplication::arguments().size() > 1)
         {
            if (QCoreApplication::arguments()[1] == "-classes")
            {
               // only print test classes
               qDebug().noquote() << testName;
               continue;
            }
            else
               if (QCoreApplication::arguments()[1] != testName)
               {
                  continue;
               }
               else
               {
                  arguments = QCoreApplication::arguments();
                  arguments.removeAt(1);
               }
         }
         else
         {
            arguments.append(QCoreApplication::arguments()[0]);
            // log to console
            arguments.append("-o"); arguments.append("-,txt");
            // log to file as TXT
            arguments.append("-o"); arguments.append(mTestLogFolder % "/" % testName % ".log,txt");
            // log to file as XML
            arguments.append("-o"); arguments.append(mTestLogFolder % "/" % testName % ".xml,xunitxml");
         }
         m_overallResult |= QTest::qExec(test, arguments);
      }
   }

   QList<QObject *> m_tests;
   int m_overallResult;
   const QString mTestLogFolder = "testLogs";
};

#endif // TESTRUNNER_H

próprio código

#include "testrunner.h"
#include "test1" 
...

#include <QDebug>

int main(int argc, char * argv[]) 
{
    TestRunner testRunner;

    //your QTest compatible class here
    testRunner.addTest(new Test1);
    testRunner.addTest(new Test2);
    ...

    bool pass = testRunner.runTests(argc, argv);
    qDebug() << "Overall result: " << (pass ? "PASS" : "FAIL");

    return pass?0:1;
}

Se você estiver usando Qt, eu recomendo usar QtTest, porque é tem instalações para testar a interface do usuário e é simples de usar.

Se você usar QtCore, provavelmente você pode fazer sem STL. I freqüentemente encontrar as classes Qt mais fácil de usar do que as contrapartes STL.

Eu apenas fui brincar com isso. A principal vantagem de usar o Google teste sobre QtTest para nós é que fazemos todo o nosso desenvolvimento UI no Visual Studio. Se você usar Visual Studio 2012 e instalar o Adapter Teste Google você pode obter VS para reconhecer os testes e incluí-los em seu Explorador de teste. Isso é ótimo para os desenvolvedores de ser capaz de usar como eles escrevem código, e porque o Google teste é portátil também pode adicionar os testes para o final de nossa construção Linux.

Eu estou esperando que no futuro que alguém vai adicionar suporte para C ++ para uma das ferramentas de teste simultâneas que C # tem, como NCrunch , Giles e ContinuousTests .

É claro, que você pode encontrar alguém escreve outro adaptador para VS2012 que adiciona QtTest suporte ao adaptador de teste, caso em que esta vantagem vai embora! Se alguém estiver interessado neste há um post bom blog Criação de um novo Visual unidade de estúdio adaptador de teste .

Para suporte ferramenta adaptador de teste Visual Studio com o QtTest uso âmbito desta extensão Visual Studio: https://visualstudiogallery.msdn.microsoft.com/cc1fcd27-4e58-4663-951f-fb02d9ff3653

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top