Quel cadre de test unitaire devrais-je utiliser pour le Qt? [fermé]

je suis en train de démarrer un nouveau projet qui a besoin d'une GUI multiplateforme, et nous avons choisi Qt comme GUI-framework.

nous avons aussi besoin d'un cadre de test unitaire. Jusqu'à il y a environ un an, nous utilisions un cadre de test unitaire développé en interne pour les projets C++, mais nous sommes en train de passer à L'utilisation de Google Test pour les nouveaux projets.

est-ce que quelqu'un a de l'expérience avec L'utilisation de Google Test pour Qt-applications? Est QtTest/QTestLib un meilleur alternative?

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

EDIT: Il ressemble à beaucoup de penchant vers QtTest. Est-ce que quelqu'un qui a une expérience de l'intégration avec un serveur d'intégration continue? Aussi, il me semble que d'avoir à gérer un distinct l'application pour chaque nouveau cas d'essai causerait beaucoup de friction. Y a-t-il un bon moyen de résoudre ça? Qt Creator a-t-il une bonne façon de gérer de tels cas de test ou auriez-vous besoin d'un projet par cas de test?

44
demandé sur kiamlaluno 2009-10-06 12:54:04

11 réponses

Je ne sais pas si QTestLib est" meilleur " qu'un cadre pour un autre en termes aussi généraux. Il y a une chose qu'il fait bien, et qui est de fournir un bon moyen de tester des 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 d'après L'architecture de QTestLib, il semble que ce ne serait pas trop compliqué.

Tests écrits avec qtestlib pure ont une option-xml que vous pourrait utiliser, avec quelques transformations XSLT pour convertir le format d'un serveur d'intégration continue. Cependant, beaucoup de cela dépend du serveur CI que vous allez avec. J'imagine que la même chose s'applique à GTest.

une seule application d'essai par étui d'essai 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 gérer la construction et l'exécution des étuis d'essai.

Je ne sais pas n'importe quoi dans Qt Creator qui nécessiterait un projet séparé par cas de test mais il aurait pu changer depuis la dernière fois que j'ai regardé Qt Creator.

je suggère aussi de rester avec QtCore et de rester à l'écart de la STL. L'utilisation de QtCore tout au long facilitera le traitement des bits de L'interface graphique qui nécessitent les types de données Qt. Vous n'aurez pas à vous soucier de convertir d'un type de données à un autre dans ce cas.

17
répondu Matt Rogers 2012-07-02 19:45:08

vous ne devez pas créer des applications de tests séparés. Il suffit d'utiliser qExec dans une fonction principale indépendante () similaire à celle-ci:

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

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

    // ...

    return 0;
}

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

votre classe de test .les fichiers h ressembleraient à ceci:

class TestClass1 : public QObject
{
Q_OBJECT

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

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

37
répondu Joe 2010-09-27 14:51:43

pour l'ajouter à la réponse de Joe.

voici un petit en-tête que j'utilise (testrunner.h), contenant une classe utilitaire qui produit une boucle d'événement (qui est, par exemple, nécessaire pour tester les connexions signal-slot et les bases de données) et des classes compatibles QTest" running":

#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 - le 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;
}
19
répondu mlvljr 2015-05-26 20:23:26

j'ai commencé à utiliser Qtttest pour mon application et très, très rapidement j'ai commencé à rencontrer des limites avec elle. Les deux principaux problèmes étaient:

1)mes tests s'exécutent très rapidement - suffisamment rapidement pour que le temps de chargement d'un exécutable, La mise en place d'une Application Q(Core) (si nécessaire) ETC éclipse souvent le temps de fonctionnement des tests eux-mêmes! Relier chaque exécutable prend beaucoup de temps, trop.

La surcharge simplement cessé d'augmenter au fur et à d'autres classes ont été ajoutées, et cela est rapidement devenu un problème - l'un des objectifs des tests unitaires est d'avoir un filet de sécurité qui fonctionne si vite que ce n'est pas un fardeau du tout, et ce n'était pas le cas rapidement. La solution consiste à regrouper plusieurs suites de test en un seul exécutable, et bien que (comme montré ci-dessus) cela soit le plus souvent faisable, il est non supporté et a des limites importantes.

2) pas de support fixe - un briseur de deal pour moi.

ainsi, après un certain temps, je suis passé à Google Test - il s'agit d'un cadre de test de l'Unité beaucoup plus fonctionnel et sophistiqué (en particulier lorsqu'il est utilisé avec Google Mock) et résout 1) et 2), et de plus, vous pouvez encore facilement utiliser les fonctionnalités pratiques de QTestLib telles que QSignalSpy et la simulation D'événements GUI, etc. C'était un peu pénible de changer, mais heureusement le projet n'avait pas avancé trop loin et beaucoup de changements pouvaient être automatisés.

personnellement, je ne serai pas utiliser Qtttest sur Google Test pour les projets futurs-si n'offre pas d'avantages réels que je peux voir, et a des inconvénients importants.

18
répondu SSJ_GZ 2015-08-29 12:08:48

pourquoi ne pas utiliser le cadre d'essais unitaires inclus dans Qt? Un exemple: Qttestlib Tutorial .

7
répondu Patrice Bernassola 2011-09-25 13:39:54

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

(Btw, je recommande fortement L'utilisation de QtCore même pour les parties non-GUI des applications. C'est beaucoup plus agréable de travailler avec.)

3
répondu Lukáš Lalinský 2009-10-06 08:59:48

pour étendre la solution mlvljr et Joe's, nous pouvons même prendre en charge les options Qtttest complètes par classe de test et exécuter tout cela dans un lot plus la journalisation:

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 /q/what-unit-testing-framework-should-i-use-for-qt-closed-39162/"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;
}
3
répondu j.holetzeck 2015-07-03 11:22:01

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

3
répondu BЈовић 2017-03-16 09:45:11

si vous utilisez Qt, je vous recommande D'utiliser QtTest, parce que is a des facilités pour tester L'UI et est simple à utiliser.

si vous utilisez QtCore, vous pouvez probablement vous passer de STL. Je trouve souvent les classes Qt plus faciles à utiliser que les classes STL.

2
répondu Gunther Piez 2009-10-06 09:51:30

j'ai juste joué avec ça. Le principal avantage de L'utilisation de Google Test sur QtTest pour nous est que nous faisons tout notre développement D'interface utilisateur dans Visual Studio. Si vous utilisez Visual Studio 2012 et installez le Google test adaptateur vous pouvez obtenir VS de reconnaître les tests et de les inclure dans son explorateur de Test. C'est génial pour les développeurs d'être en mesure d'utiliser comme ils écrivent du code, et parce que Google Test est portable, nous pouvons également ajouter les tests à la fin de notre Linux construire.

j'espère qu'à l'avenir quelqu'un ajoutera du support pour C++ à l'un des outils de test concurrents 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 Qtttest à L'Adaptateur de Test dans lequel cas cet avantage disparaît! Si quelqu'un est intéressé par ceci, Il ya un bon billet de blog la Création d'un nouveau Visual studio unité d'adaptateur de test .

1
répondu parsley72 2013-02-19 19:39:32

pour Visual Studio Test adaptateur prise en charge de l'outil avec le cadre QtTest utilisez cette extension Visual Studio: https://visualstudiogallery.msdn.microsoft.com/cc1fcd27-4e58-4663-951f-fb02d9ff3653

0
répondu user3395798 2015-11-06 19:44:09