Question

Je commence un nouveau projet qui a besoin d'une interface graphique multi-plateforme, et nous avons choisi Qt comme l'interface graphique-cadre.

Nous avons besoin d'un cadre de tests unitaires, aussi. Jusqu'à il y a environ un an, nous avons utilisé un cadre du test par unité développée en interne pour C ++ - projets, mais nous sommes maintenant en train de passer à l'utilisation de test Google pour de nouveaux projets

.

Quelqu'un at-il une expérience avec l'utilisation de test Google pour les applications Qt-? Est-QtTest / QTestLib une meilleure alternative?

Je ne suis toujours pas sûr à quel point nous voulons utiliser Qt dans les parties non-GUI du projet - nous préférerions probablement utiliser simplement STL / Boost dans le code de base avec une petite interface à l'interface graphique basée sur Qt .

EDIT: Il ressemble beaucoup se penchent vers QtTest. Est-ce qu'il ya quelqu'un qui a une expérience avec son intégration avec un serveur d'intégration continue? En outre, il me semble que d'avoir à gérer une demande distincte pour chaque nouveau cas de test causerait beaucoup de frictions. Y at-il un bon moyen de résoudre cela? Est-ce que Qt Creator a une bonne façon de traiter ces cas de test ou auriez-vous besoin d'avoir un projet par cas de test?

Était-ce utile?

La solution

Je ne sais pas que QTestLib est « meilleur » que l'un cadre pour un autre en termes généraux. Il y a une chose qu'il fait bien, et qui est de fournir un bon moyen de tester les applications basées sur Qt.

Vous pouvez intégrer QTest dans votre nouvelle configuration basée sur Google Test. Je ne l'ai pas essayé, mais basé sur la façon dont QTestLib est architecturé, il semble que ce ne serait pas trop compliqué.

Les tests écrits avec pur QTestLib ont une option -xml que vous pouvez utiliser, ainsi que quelques transformations XSLT pour convertir au format nécessaire pour un serveur d'intégration continue. Cependant, beaucoup de cela dépend de quel serveur CI vous allez avec. J'imagine de même pour gtest.

Une application de test unique par cas de test n'a jamais causé beaucoup de friction pour moi, mais cela dépend d'avoir un système de construction qui ferait un travail décent de gestion de l'immeuble et de l'exécution des cas de test.

Je ne sais pas de quoi que ce soit dans Qt Creator qui nécessiterait un projet séparé par cas de test, mais il aurait pu changé depuis la dernière fois que je regardais Qt Creator.

Je suggère également coller avec QtCore et de rester loin de la STL. L'utilisation QtCore fera tout au long de traiter les bits de l'interface graphique qui nécessitent les données Qt types plus facile. Vous n'aurez pas à vous soucier de la conversion d'un type de données à un autre dans ce cas.

Autres conseils

Vous ne disposez pas de créer des applications distinctes tests. Il suffit d'utiliser qExec dans une fonction principale () indépendante similaire à celui-ci:

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

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

    // ...

    return 0;
}

exécutera toutes les méthodes d'essai dans chaque classe en un seul lot.

Les fichiers de votre TestClass se présente comme suit:

class TestClass1 : public QObject
{
Q_OBJECT

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

Malheureusement, cette configuration est pas vraiment bien décrit dans la documentation Qt, même si elle semble être très utile pour beaucoup de gens.

Pour ajouter à la réponse de Joe.

Voici un petit tête que j'utilise (testrunner.h), contenant une classe d'utilité fraie une boucle d'événement (qui est, par exemple, nécessaire pour tester les connexions signal-slot et bases de données en file d'attente) et « en cours d'exécution » des classes QTest compatibles:

#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

Utilisez comme ceci:

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

J'ai commencé à l'aide QtTest pour mon application et très, très rapidement commencé à courir dans les limites avec elle. Les deux principaux problèmes sont les suivants:

1) Mes tests courent très vite - assez rapidement que la surcharge de chargement d'un exécutable, la mise en place d'un Q (noyau) Application (si nécessaire), etc souvent le temps rapetisse en cours d'exécution des tests eux-mêmes! Lier chaque exécutable prend beaucoup de temps, aussi.

Les frais généraux a juste continué à augmenter au fur et à plusieurs classes ont été ajoutées, et il est vite devenu un problème - l'un des objectifs des tests unitaires doivent avoir un filet de sécurité qui fonctionne si vite qu'il ne soit pas du tout un fardeau, et cela devenait rapidement le cas contraire. La solution est à glob plusieurs suites de test en un seul exécutable, et tout (comme indiqué ci-dessus), cela est faisable, il est surtout pas pris en charge et a des limites importantes.

2) Pas de support de fixation -. Un deal-breaker pour moi

Alors, après un certain temps, je suis passé à Google Test - il est un cadre de tests unitaires beaucoup plus featureful et sophistiqué (surtout lorsqu'il est utilisé avec Google Mock) et permet de résoudre 1) et 2), et de plus, vous pouvez toujours utiliser facilement la caractéristiques QTestLib pratiques telles que QSignalSpy et simulation d'événements de l'interface graphique, etc. Il était un peu difficile de changer, mais heureusement le projet n'a pas avancé trop loin et beaucoup des changements pourraient être automatisées.

Personnellement, je ne vais pas utiliser QtTest sur Google test pour les projets futurs - si sans véritable avantages que je peux voir, et présente des inconvénients importants

.

Pourquoi ne pas utiliser le cadre du test par unité inclus dans Qt? Un exemple:. QtTestLib Tutorial

unité I testé nos bibliothèques en utilisant gtest et QSignalSpy . Utilisez QSignalSpy pour attraper des signaux. Vous pouvez appeler directement les fentes (comme les méthodes normales) pour les tester.

QtTest est surtout utile pour tester des pièces qui nécessitent la boucle d'événements Qt / dispatching de signal. Il est conçu de manière à ce que chaque cas de test nécessite un exécutable séparé, donc il ne devrait pas entrer en conflit avec un cadre de test existant utilisé pour le reste de l'application.

(BTW, je vous recommande fortement d'utiliser QtCore même pour les parties non-GUI des applications. Il est beaucoup plus agréable de travailler avec.)

Pour prolonger des années mlvljr et la solution de Joe nous pouvons même soutenir les options complètes de QtTest par une classe de test et toujours courir le tout dans un lot plus de l'enregistrement:

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

En-tête

#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

propre code

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

Si vous utilisez Qt, je vous conseille d'utiliser QtTest, car est-a des installations pour tester l'interface utilisateur et est simple à utiliser.

Si vous utilisez QtCore, vous pouvez probablement faire sans STL. Je trouve souvent les classes Qt plus facile à utiliser que les homologues de la STL.

Je viens de jouer avec cela. Le principal avantage de l'utilisation de Google test sur QtTest pour nous est que nous faisons tout notre développement de l'interface utilisateur dans Visual Studio. Si vous utilisez Visual Studio 2012 et installer le Google adaptateur de test peut obtenir VS reconnaître les essais et les inclure dans son test Explorer. C'est idéal pour les développeurs pour pouvoir l'utiliser comme ils écrivent le code, et parce que Google Test est portable, nous pouvons également ajouter les tests à la fin de notre version de Linux.

J'espère à l'avenir que quelqu'un va ajouter le support pour C ++ à l'un des outils de tests simultanés que C # ont, comme NCrunch , Giles et ContinuousTests .

Bien sûr, vous pourriez trouver quelqu'un écrit un autre adaptateur pour VS2012 qui ajoute le support QtTest à l'adaptateur de test dans ce cas, cet avantage va! Si quelqu'un est intéressé à cela, il y a un bon blog auteur d'un nouvel adaptateur de test unité de Visual studio .

Pour le support de l'outil adaptateur de test Visual Studio avec le cadre QtTest utiliser cette extension Visual Studio: https://visualstudiogallery.msdn.microsoft.com/cc1fcd27-4e58-4663-951f-fb02d9ff3653

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top