Que Quadro de testes unitários devo usar para o Qt? [fechado]

estou a iniciar um novo projecto que precisa de uma interface multi-plataforma, e escolhemos o Qt como o GUI-framework.

Também precisamos de um quadro de testes unitários. Até cerca de um ano atrás usamos um framework de testes de unidade desenvolvido internamente para projetos C++, mas agora estamos transitando para o uso do Teste Google para novos projetos.

alguém tem alguma experiência com a utilização do Teste Google para aplicações Qt? O QtTest / QTestLib é uma alternativa melhor?

ainda não estou claro quanto nós queremos usar o Qt nas partes não-GUI do projeto - nós provavelmente preferiríamos apenas usar STL/Boost no core-code com uma pequena interface para a GUI baseada no Qt.

EDIT: parece que muitos estão a inclinar-se para o QtTest. Há alguém que tenha alguma experiência em integrar isso com um servidor de integração contínua? Além disso, parece-me que ter de lidar com uma aplicação separada para cada novo caso de teste causaria muito atrito. Há alguma coisa boa? que maneira de resolver isso? O Qt Creator tem uma boa maneira de lidar com esses casos de teste ou você precisa ter um projeto por caso de teste?

Author: kiamlaluno, 2009-10-06

11 answers

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

Pode integrar o QTest na sua nova configuração baseada no Google Test. Eu não tentei, mas baseado em como QTestLib é arquitetado, parece que não seria muito complicado.

Os testes escritos com o QTestLib puro têm uma opção-xml que poderá usar, juntamente com algum XSLT transformações para converter para o formato necessário para um servidor de integração contínua. No entanto, muito disso depende de que servidor CI você vai com. Imagino que o mesmo se aplica ao GTest.

Um único aplicativo de teste por caso de teste nunca causou muita fricção para mim, mas isso depende de ter um sistema de construção que faria um trabalho decente de gerenciar a construção e execução dos casos de teste. Não sei de nada no Qt Creator que requeira um projecto separado por teste. caso, mas podia ter mudado desde a última vez que olhei para o Qt Creator. Eu também sugeria ficar com o QtCore e ficar longe do STL. Usar o QtCore por todo o lado tornará mais fácil lidar com os bits GUI que requerem os tipos de dados Qt. Você não terá que se preocupar em converter de um tipo de dados para outro nesse caso.
 17
Author: Matt Rogers, 2012-07-02 19:45:08
Não tem de criar aplicações de testes separadas. Basta usar o qExec numa 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 de um lote.

A sua classe de teste .os ficheiros h seriam os seguintes:

class TestClass1 : public QObject
{
Q_OBJECT

private slots:
    void testMethod1();
    // ...
}
Infelizmente, esta configuração não está muito bem descrita na documentação do Qt, apesar de parecer ser bastante útil para muitas pessoas.
 37
Author: Joe, 2010-09-27 14:51:43
Juntar à resposta do Joe.

Aqui está um pequeno cabeçalho que eu uso (testrunner.h), contendo uma classe de utilidade que gera um ciclo de eventos (que é, por exemplo, necessário para testar conexões de sinal em fila de espera e bases de dados) e classes" executando " 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

Usa-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;
}
 19
Author: mlvljr, 2015-05-26 20:23:26

Comecei a usar o QtTest para o meu aplicativo e muito, muito rapidamente comecei a ter limitações com ele. Os dois principais problemas foram:

1) Os meus testes são muito rápidos-suficientemente rápidos para que a sobrecarga de carregar um executável, configurar uma aplicação Q(Core) (se necessário), etc, diminua frequentemente o tempo de execução dos próprios testes! Ligar cada executável leva muito tempo também.

A sobrecarga continuou a aumentar à medida que mais e mais classes eram adicionadas, e logo se tornou um problema-um dos objetivos dos testes unitários é ter uma rede de segurança que funciona tão rápido que não é um fardo de todo, e isso rapidamente não estava se tornando o caso. A solução é globar múltiplas suites de teste em um executável, e enquanto (Como mostrado acima) isso é principalmente capaz de fazer, ele é não suportado e tem limitações importantes. Sem suporte de fixação, Não tenho acordo. Então, passado algum tempo, mudei para o teste do Google-é muito mais difícil e sofisticada estrutura de teste de unidade (especialmente quando usada com Google Mock) e resolve 1) e 2), e além disso, você ainda pode facilmente usar as funcionalidades de qtestlib úteis, tais como QSignalSpy e simulação de eventos GUI, etc. Foi um pouco difícil mudar, mas felizmente o projeto não tinha avançado muito e muitas das mudanças poderiam ser automatizadas.

Pessoalmente, não vou usar o QtTest sobre o teste do Google para projectos futuros-se não oferecer vantagens reais que eu possa ver, e tem desvantagens importantes.

 18
Author: SSJ_GZ, 2015-08-29 12:08:48

Porque não usar a estrutura de testes de unidade incluída no Qt? Um exemplo: Qttestlib Tutorial .

 7
Author: Patrice Bernassola, 2011-09-25 13:39:54

O QtTest é, na sua maioria, útil para testar as partes que necessitam do 'Qt event loop' / 'signal dispatching'. Ele é projetado de uma forma que cada caso de teste requer um executável separado, então ele não deve entrar em conflito com qualquer estrutura de teste existente usado para o resto da aplicação.

(Btw, eu recomendo muito o uso de QtCore mesmo para partes não-GUI das aplicações. É muito melhor trabalhar com ele.)

 3
Author: Lukáš Lalinský, 2009-10-06 08:59:48

Para extender a solução do mlvljr e do Joe, podemos até mesmo suportar opções completas do QtTest por uma classe de teste e ainda executar tudo num lote mais registo:

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]]...

Cabeçalho

#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

Código próprio

#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;
}
 3
Author: j.holetzeck, 2015-07-03 11:22:01

A unidade I testou as nossas bibliotecas usando o gtest e O QSignalSpy . Use o QSignalSpy para apanhar sinais. Você pode chamar slots diretamente (como métodos normais) para testá-los.

 3
Author: BЈовић, 2017-03-16 09:45:11

Se está a usar o Qt, eu recomendaria o uso do QtTest, porque o is tem instalações para testar a IU e é simples de usar.

Se usar o QtCore, pode passar sem STL. Eu frequentemente acho as classes Qt mais fáceis de usar do que as contrapartes STL.

 2
Author: Gunther Piez, 2009-10-06 09:51:30
Tenho andado a brincar com isto. A principal vantagem de usar o teste Google sobre QtTest para nós é que fazemos todo o nosso desenvolvimento UI em Visual Studio. Se utilizar o Visual Studio 2012 e instalar o Google Test Adapter, poderá pedir ao VS para reconhecer os testes e incluí-los no seu Test Explorer. Isso é ótimo para os desenvolvedores serem capazes de usar como eles escrevem código, e como o Google Test é portátil, nós também podemos adicionar os testes ao final de nossa construção Linux.

Eu sou esperando no futuro que alguém adicione suporte para C++ a uma das ferramentas de teste simultâneas que o C# tem, como NCrunch, Giles e continuam a investigar .

Claro, você pode encontrar alguém que escreve outro adaptador para VS2012 que adiciona suporte QtTest para testar o adaptador, caso em que esta vantagem desaparece! Se alguém estiver interessado nisto, há um bom post no blog a criar um novo adaptador de teste Visual studio unit.

 1
Author: parsley72, 2013-02-19 19:39:32

Para Suporte de Ferramenta de adaptador Visual Studio com o qttest framework use esta extensão Visual Studio: https://visualstudiogallery.msdn.microsoft.com/cc1fcd27-4e58-4663-951f-fb02d9ff3653

 0
Author: user3395798, 2015-11-06 19:44:09