Domanda

Ho iniziato a scrivere alcuni test con il sistema di test delle unità di Qt.

Di solito come organizzare i test? Si tratta di una classe di test per un modulo di classe, o si fa a testare l'intero modulo con una sola classe di test? docs Qt suggeriscono di seguire la prima strategia.

Voglio scrivere test per un modulo. Il modulo fornisce solo una classe che sta per essere utilizzato dall'utente del modulo, ma c'è un sacco di logica astratta in altre classi, che vorrei anche a prova, oltre a testare la classe pubblico.

Il problema è che propone modo di Qt per eseguire i test ha coinvolto la macro QTEST_MAIN:

QTEST_MAIN(TestClass)
#include "test_class.moc"

e, infine, un programma di test è in grado di testare una sola classe di test. E mi fa schifo un pò per creare progetti di test per ogni singola classe nel modulo.

Naturalmente, si potrebbe prendere uno sguardo al macro QTEST_MAIN, riscriverlo, ed eseguire altre classi di test. Ma c'è qualcosa, che funziona out of the box?

Finora lo faccio a mano:

#include "one.h"
#include "two.h"

int main(int argc, char *argv[]) 
{ 
    QCoreApplication app(argc, argv); 
    TestOne one;
    QTest::qExec(&one, argc, argv);
    TestOne two;
    QTest::qExec(&two, argc, argv);
}
È stato utile?

Soluzione

Si, le forze Qtest po 'strano struttura di prova ed è generalmente inferiore a Google prova / Mock Framework. Per un progetto sono costretto a utilizzare QTest (requisito del cliente), ed ecco come lo uso:

  1. compilo tutti i test insieme come un modello di progetto subdir
  2. Per rendere la creazione di nuovi test più facile, condivido un sacco di configurazione di progetto utilizzando il file common.pri includo nel file di ogni prova .pro
  3. Se possibile quota Ho la directory file oggetto per accelerare la compilazione
  4. corro tutti utilizzando un lotto + awk + script sed.

La creazione di tale quattro punti è molto semplice e rende l'utilizzo di QTest quasi piacevole. Hai qualche problema con l'esecuzione di più prove che non sono risolti con la configurazione sopra descritte?

PS:. L'esecuzione di test il modo di fare, cioè chiamando multipla QTest :: qExec causa problemi con riga di comando -o - si otterrà solo i risultati per l'ultima classe testato

Altri suggerimenti

In relazione alla risposta pubblicato da @cjhuitt

Questo è un esempio che elimina la necessità di chiamare manualmente ogni oggetto di prova

Cerco di evitare cose come questa:

MyTestClass1 t1;   t1.run();
MyTestClass2 t2;   t2.run();
//etc...

La mia soluzione è quella di lasciare che il test di oggetti ereditare da una classe base che si aggiunge a una lista statica Il programma principale esegue quindi tutti gli oggetti di prova in quella lista. In questo modo, nessuna delle esigenze di codice quadro di supporto da modificare. Le uniche cose che il cambiamento sono le classi di test stessi.

Ecco come lo faccio:

qtestsuite.h - classe base per il test degli oggetti

#ifndef QTESTSUITE_H
#define QTESTSUITE_H

#include <QObject>
#include <vector>

class QTestSuite : public QObject
{
    Q_OBJECT
public:
    static std::vector<QObject*> m_suites;

public:
    explicit QTestSuite();

};

#endif // QTESTSUITE_H

qtestsuite.cpp

#include "qtestsuite.h"
#include <iostream>

std::vector<QObject*> QTestSuite::m_suites;

QTestSuite::QTestSuite() : QObject()
{
    m_suites.push_back(this);
}

testall.cpp - esegue i test

#include "qtestsuite.h"

#include <QtTest/QtTest>
#include <iostream>

int main(int, char**)
{
    int failedSuitesCount = 0;
    std::vector<QObject*>::iterator iSuite;
    for (iSuite = QTestSuite::m_suites.begin(); iSuite != QTestSuite::m_suites.end(); iSuite++)
    {
        int result = QTest::qExec(*iSuite);
        if (result != 0)
        {
            failedSuitesCount++;
        }
    }
    return failedSuitesCount;
}

mytestsuite1.cpp - un oggetto di prova esempio, creare più di questi

#include "qtestsuite.h"

#include <QtTest/QtTest>

class MyTestSuite1: public QTestSuite
{
     Q_OBJECT
private slots:
    void aTestFunction();
    void anotherTestFunction();
};

void MyTestSuite1::aTestFunction()
{
    QString str = "Hello";
    QVERIFY(str.toUpper() == "this will fail");
}

void MyTestSuite1::anotherTestFunction()
{
    QString str = "Goodbye";
    QVERIFY(str.toUpper() == "GOODBYE");
}

static MyTestSuite1 instance;  //This is where this particular test is instantiated, and thus added to the static list of test suites

#include "mytestsuite1.moc"

Inoltre, per creare il file .pro

qmake -project "CONFIG += qtestlib"

Nella nostra messa a punto con QTest, abbiamo fatto alcune cose per renderlo più bello.

  • Definire una sottoclasse di QObject utilizzata come classe base per qualsiasi nuova classe unità-test.
  • Nel costruttore per quella classe, si aggiunge l'istanza di prova per un elenco statico di test, e nel distruttore abbiamo rimuoverlo.
  • Abbiamo poi hanno una funzione statica che loop attraverso le prove e le piste utilizzando QTest::qExec(). (Noi accumuliamo i valori restituiti ogni volta, e ritorno che dalla nostra funzione.)
  • main() chiama questa funzione, e restituisce il risultato come il successo / insuccesso.
  • Infine, in unità di compilazione del test specifico in sé, di solito includono un'istanza statica di quella classe.

Questo significa che la classe di impostazione sarà un'istanza prima main() viene eseguito, in modo che sarà aggiunto alla lista delle classi di test quando principale corre. Il quadro richiede che basta per ereditare la classe correttamente, e istanziare un'istanza statica se si vuole sempre correre.

occasionalmente creare altre prove facoltative, che vengono aggiunti basato su opzioni della riga di comando.

Di solito organizzare test con un unico eseguibile di prova per classe in prova.

  

e, infine, un programma di test è   grado di testare solo test   Classe.

Questa è una buona cosa. Si isola i test gli uni dagli altri, evitando le cose come un incidente in un test di bloccare tutte le altre prove. Questo incidente potrebbe essere causato da un componente comune a più classi in prova. Il modello dei fallimenti sarebbe poi punta voi fuori all'origine di fondo del problema. In sostanza, si dispone di informazioni migliore diagnostica per gli errori, se i test sono indipendenti l'uno dall'altro.

Lo rendono facile da installare più eseguibili ed eseguire ogni test separatamente. Utilizzare un test runner per deporre le uova di sconto su tutti i processi di test.

Aggiornamento:

Ho cambiato idea su questo un po '. Una volta che avete un grande programma con un sacco di test, che collega centinaia di eseguibili test diventa molto lento. La mia nuova preferenza è quello di mettere tutti i test per una libreria in un file eseguibile e scegliere quale test per richiamare utilizzando gli argomenti della riga di comando passati al file eseguibile di prova.

che taglia verso il basso il numero di eseguibili da centinaia a decine, ma mantiene i vantaggi di eseguire i test a parte.

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