Domanda

Io sono solo in fase di avvio un nuovo progetto che ha bisogno di qualche GUI cross-platform, e abbiamo scelto Qt come la GUI-quadro.

Abbiamo bisogno di un quadro di unit test, anche. Fino a circa un anno fa, abbiamo utilizzato un framework di unit test in-house sviluppato per C ++ - progetti, ma ora siamo la transizione a utilizzare Google prova per i nuovi progetti

.

Qualcuno ha qualche esperienza con l'utilizzo di Google prova per Qt-applicazioni? QtTest / QTestLib è un'alternativa migliore?

Sono ancora non so quanto vogliamo usare Qt nelle parti non-GUI del progetto - probabilmente avremmo preferito utilizzare solo STL / Boost nel nucleo-codice con una piccola interfaccia per la GUI Qt-based .

EDIT: Sembra che molti sono sporgendosi verso QtTest. C'è qualcuno che ha qualche esperienza con l'integrazione di questo con un server di integrazione continua? Inoltre, sembrerebbe a me che dover gestire una domanda separata per ogni nuovo caso di test potrebbe causare un sacco di attrito. C'è un buon modo per risolvere questo? Ha Qt Creator hanno un buon modo di gestire tali casi di test o sarebbe è necessario avere un progetto per ogni banco di prova?

È stato utile?

Soluzione

Non so che QTestLib è "migliore" di un quadro per un altro in termini così generali. C'è una cosa che lo fa bene, e questo è di fornire un buon modo per testare applicazioni basate su Qt.

Si potrebbe integrare QTest nella nuova configurazione basata Google prova. Non ho provato, ma in base a come QTestLib è progettato, sembra che non sarebbe troppo complicato.

I test scritti con puro QTestLib hanno un'opzione -xml che si potrebbe usare, insieme ad alcune trasformazioni XSLT per convertire nel formato necessario per un server di integrazione continua. Tuttavia, un sacco di che dipende da quale server CI si va con. Immagino lo stesso vale per GTEST.

Una singola applicazione di test per ogni caso di test non ha causato un sacco di attrito per me, ma che dipende da avere un sistema di compilazione che avrebbe fatto un lavoro decente di gestire la costruzione e l'esecuzione dei casi di test.

Non so di nulla in Qt Creator che richiederebbe un progetto separato per ogni banco di prova ma avrebbe potuto cambiato dall'ultima volta che ho guardato Qt Creator.

Vorrei anche suggerire attaccare con QtCore e stare lontano dalla STL. Utilizzando QtCore tutto farà fare con i bit GUI che richiedono i tipi di dati Qt più facile. Non dovrete preoccuparvi di conversione da un tipo di dati a un altro in quel caso.

Altri suggerimenti

Non è necessario per creare applicazioni test separati. Basta usare qExec in una funzione indipendente main () simile a questo:

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

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

    // ...

    return 0;
}

Questo eseguirà tutti i metodi di prova di ogni classe in un unico lotto.

Il tuo file TestClass .h modo simile al seguente:

class TestClass1 : public QObject
{
Q_OBJECT

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

Purtroppo questa impostazione non è realmente descritto bene nella documentazione Qt, anche se sembrerebbe essere molto utile per un sacco di gente.

Per aggiungere alla risposta di Joe.

Ecco un breve intestazione che uso (testrunner.h), contenente una classe di utilità generando un ciclo di eventi (che è, ad esempio, necessario per testare accodati connessioni segnale slot e database) e "marcia" classi compatibili QTest:

#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

Si usa in questo modo:

#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;
}

Ho cominciato usando QtTest per la mia app e molto, molto rapidamente iniziato a correre in limitazioni con esso. I due problemi principali erano:

1) I miei test eseguiti molto velocemente - in modo sufficientemente rapido che il sovraccarico di caricamento di un file eseguibile, la creazione di un Q (Core) Applicazione (se necessario), ecc spesso nani il tempo di esecuzione dei test stessi! Collegando ogni eseguibile prende un sacco di tempo, troppo.

L'overhead continuava ad aumentare cui sono stati aggiunti sempre di più classi, e divenne ben presto un problema - uno degli obiettivi di test di unità sono di avere una rete di sicurezza che corre così veloce che non è un peso a tutti, e questo è stato rapidamente diventando non il caso. La soluzione è glob multipli suite di test in un unico eseguibile, e mentre (come indicato sopra) questo è principalmente fattibile, è non supportato e ha importanti limitazioni.

2) Nessun supporto di fissaggio -. Un affare-breaker per me

Così, dopo un po ', sono passato a Google prova - si tratta di un framework di test unità di gran lunga più ricco di funzioni e sofisticato (soprattutto quando viene utilizzato con Google Mock) e risolve 1) e 2), e per di più, si può ancora usare facilmente le funzioni utili QTestLib quali QSignalSpy e la simulazione di eventi GUI, ecc e 'stato un po' di dolore per cambiare, ma per fortuna il progetto non avevano avanzato troppo lontano e molti dei cambiamenti potrebbero essere automatizzate.

Personalmente, non sarò con QtTest su Google prova per i progetti futuri - se non offre alcun vantaggio reale che posso vedere, e ha importanti inconvenienti

.

Perché non utilizzando il framework di unit test inclusi in Qt? Un esempio:. QtTestLib Tutorial

Unità ho provato le nostre biblioteche con GTEST e QSignalSpy . Utilizzare QSignalSpy per la cattura di segnali. È possibile chiamare direttamente gli slot (come i metodi normali) per metterli alla prova.

QtTest è soprattutto utile per testare le parti che richiedono l'/ invio del segnale Qt ciclo di eventi. È progettato in modo tale che ogni test richiede un eseguibile separato, quindi non dovrebbe entrare in conflitto con qualsiasi quadro di prova esistente utilizzato per il resto dell'applicazione.

(Btw, mi raccomando usando QtCore anche per le parti non GUI delle applicazioni. E 'molto più bello con cui lavorare.)

Per estendere mlvljr di e la soluzione di Joe possiamo anche sostenere opzioni complete QtTest per una classe di test e ancora correre il tutto in un lotto più di registrazione:

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

Intestazione

#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

proprio codice

#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 si utilizza Qt, mi consiglia di utilizzare QtTest, perché è ha strutture per testare l'interfaccia utente ed è semplice da usare.

Se si utilizza QtCore, probabilmente si può fare a meno di STL. Mi capita spesso di trovare le classi Qt più facile da usare rispetto alle controparti STL.

Ho appena giocato in giro con questo. Il principale vantaggio di utilizzare Google prova sopra QtTest per noi è che noi facciamo tutto il nostro sviluppo dell'interfaccia utente in Visual Studio. Se si utilizza Visual Studio 2012 e installare il Google prova adattatore voi può ottenere VS di riconoscere i test e includerli nel suo Explorer test. Questo è grande per gli sviluppatori siano in grado di utilizzare come scrivono codice e perché Google prova è portatile possiamo anche aggiungere i test alla fine della nostra costruzione Linux.

Spero in futuro che qualcuno aggiungerà il supporto per C ++ per uno degli strumenti di test simultanei che C # hanno, come NCrunch , Giles e ContinuousTests .

Naturalmente, si potrebbe trovare qualcuno scrive un altro adattatore per VS2012 che aggiunge il supporto per QtTest Test Adapter nel qual caso questo vantaggio va via! Se qualcuno è interessato a questo c'è una buona post sul blog Authoring un nuovo Visual unità di studio adattatore di prova .

Per Visual Studio Test strumento di supporto adattatore con il quadro QtTest utilizzare questa estensione di Visual Studio: https://visualstudiogallery.msdn.microsoft.com/cc1fcd27-4e58-4663-951f-fb02d9ff3653

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top