Pregunta

Recién estoy iniciando un nuevo proyecto que necesita una GUI multiplataforma y hemos elegido Qt como marco de GUI.

También necesitamos un marco de pruebas unitarias.Hasta hace aproximadamente un año usábamos un marco de pruebas unitarias desarrollado internamente para proyectos C++, pero ahora estamos haciendo la transición al uso de Google Test para nuevos proyectos.

¿Alguien tiene alguna experiencia con el uso de Google Test para aplicaciones Qt?¿Es QtTest/QTestLib una mejor alternativa?

Todavía no estoy seguro de cuánto queremos usar Qt en las partes del proyecto que no son GUI; probablemente preferiríamos usar STL/Boost en el código central con una pequeña interfaz para la GUI basada en Qt.

EDITAR: Parece que muchos se inclinan por QtTest.¿Hay alguien que tenga alguna experiencia en la integración de esto con un servidor de integración continua?Además, me parece que tener que manejar una aplicación separada para cada nuevo caso de prueba causaría mucha fricción.¿Hay alguna buena manera de resolver eso?¿Qt Creator tiene una buena manera de manejar dichos casos de prueba o necesitaría tener un proyecto por caso de prueba?

¿Fue útil?

Solución

No sé que QTestLib es "mejor" de un marco para la otra en términos tan generales. Hay una cosa que lo hace bien, y eso es proporcionar una buena manera de probar las aplicaciones basadas en Qt.

Se podría integrar QTest en su nueva configuración basada en la prueba de Google. Yo no lo he probado, pero en base a la forma posee una arquitectura QTestLib, parece que no sería demasiado complicado.

Las pruebas escritas con pura QTestLib tienen una opción -xml que se puede utilizar, junto con algunas transformaciones XSLT para convertir al formato necesario para un servidor de integración continua. Sin embargo, mucho de eso depende del servidor CI vas con. Me imagino que lo mismo se aplica a GTEST.

Una aplicación de prueba individual por caso de prueba no causó mucha fricción para mí, pero eso depende de tener un sistema de construcción que hacer un trabajo decente de la gestión de la construcción y ejecución de los casos de prueba.

No sé de nada en Qt Creator que requeriría un proyecto independiente por cada caso de prueba pero podría haber cambiado desde la última vez que miraba a Qt Creator.

Me gustaría también sugieren la pervivencia de QtCore y mantenerse alejado de la STL. Usando QtCore lo largo hará que tratar con los bits de interfaz gráfica de usuario que requieren los tipos de datos de Qt más fácil. Usted no tendrá que preocuparse por la conversión de un tipo de datos a otro en ese caso.

Otros consejos

No es necesario para crear aplicaciones de pruebas por separado. Sólo tiene que utilizar qExec en una función independiente main () similar a ésta:

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

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

    // ...

    return 0;
}

Esto ejecutará todos los métodos de prueba en cada clase en un lote.

Su TestClass archivos .h se vería de la siguiente manera:

class TestClass1 : public QObject
{
Q_OBJECT

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

Por desgracia, esta configuración no está muy bien descrito en la documentación de Qt a pesar de que parece ser bastante útil para mucha gente.

Para añadir a la respuesta de Joe.

He aquí una pequeña cabecera utilizo (testrunner.h), que contiene una clase de utilidad desove un bucle de eventos (que es, por ejemplo, necesario para probar conexiones y bases de datos de intervalo de la señal en cola) y "funcionamiento" clases compatibles con 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

Utilice esta manera:

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

Empecé usando QtTest para mi aplicación y muy, muy rápidamente empecé a correr en las limitaciones con él. Los dos problemas principales son:

1) Mis pruebas se ejecutan muy rápido - con la suficiente rapidez que la sobrecarga de cargar un archivo ejecutable, la creación de una aplicación Q (Core) (si es necesario), etc menudo eclipsa el tiempo de ejecución de las mismas pruebas! La vinculación de cada ejecutable ocupa mucho tiempo, también.

La sobrecarga simplemente siguió aumentando a medida que se añaden más y más clases, y pronto se convirtió en un problema - uno de los objetivos de las pruebas unitarias son tener una red de seguridad que corre tan rápido que no es una carga en absoluto, y esto fue rápidamente, no convirtiendo el caso. La solución es a glob múltiples conjuntos de pruebas en un ejecutable, y mientras (como se muestra más arriba) Esto es sobre todo hacer de poder, es no soportado y tiene limitaciones importantes.

2) No hay soporte accesorio -. Rompe el acuerdo para mí

Así que después de un tiempo, me pasa a Google prueba - se trata de un marco de pruebas de unidad mucho más featureful y sofisticado (especialmente cuando se utiliza con Google Mock) y resuelve 1) y 2), y por otra parte, todavía se puede utilizar simplemente las QTestLib características útiles, tales como QSignalSpy y simulación de eventos GUI, etc. fue un poco de dolor para cambiar, pero por suerte el proyecto no habían avanzado demasiado y muchos de los cambios podrían ser automatizado.

En lo personal, no me va a utilizar QtTest sobre Google prueba para futuros proyectos - si no ofrece ventajas reales que puedo ver, y tiene inconvenientes importantes

.

¿Por qué no usar el marco de pruebas de unidad incluidos en Qt? Un ejemplo:. QtTestLib Tutorial

Unidad de prueba que nuestras bibliotecas usando GTEST y QSignalSpy . Utilice QSignalSpy para atrapar señales. Puede llamar directamente ranuras (como métodos normales) para ponerlos a prueba.

QtTest es sobre todo útil para probar piezas que requieren el / despacho señal Qt bucle de eventos. Está diseñado de tal manera que cada caso de prueba requiere un ejecutable independiente, por lo que no debe entrar en conflicto con cualquier marco de pruebas existente utilizado para el resto de la aplicación.

(Por cierto, recomiendo encarecidamente utilizar QtCore incluso para partes no gráficos de las aplicaciones. Es mucho más agradable para trabajar.)

Para extender de mlvljr y solución de Joe incluso podemos apoyar opciones QtTest completas por una clase de prueba y seguir ejecutando todo en un lote más el registro:

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

Código propia

#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 está utilizando Qt, yo recomendaría usar QtTest, debido a que se cuenta con instalaciones para probar la interfaz de usuario y es fácil de usar.

Si utiliza QtCore, es probable que pueda prescindir de STL. Con frecuencia me encuentro las clases Qt fácil de usar que las contrapartes STL.

He estado jugando con esto. La principal ventaja de utilizar Google prueba sobre QtTest para nosotros es que hagamos todo nuestro desarrollo de interfaz de usuario en Visual Studio. Si utiliza Visual Studio 2012 e instalar el Prueba adaptador Google se puede obtener VS reconocer las pruebas e incluirlos en su Explorador de prueba. Esto es grande para que los desarrolladores puedan utilizar ya que escribir código, y porque Google prueba es portátil también puede añadir las pruebas para el final de nuestra acumulación de Linux.

Espero que en el futuro que alguien va a añadir soporte para C ++ para una de las herramientas de pruebas simultáneas que tienen C #, como NCrunch , Giles y ContinuousTests .

Por supuesto, es posible encontrar a alguien escribe otro adaptador para VS2012 que añade soporte QtTest al adaptador de prueba, en cuyo caso esta ventaja desaparece! Si alguien está interesado en este hay una buena entrada en el blog creación de un proyecto nuevo de Visual unidad de estudio adaptador de prueba .

Para Estudio prueba el apoyo visual herramienta de adaptador con el marco QtTest utilizar esta extensión de Visual Studio: https://visualstudiogallery.msdn.microsoft.com/cc1fcd27-4e58-4663-951f-fb02d9ff3653

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top