example2.pro
TEMPLATE = app
CONFIG = qt warn_on debug
unix:LIBS = -L../qcppunit -lqcppunit
INCLUDEPATH = ../qcppunit ../qcppunit/testlib
HEADERS = \
mainWindow.h
SOURCES = \
main.cpp \
mainWindow.cpp
TARGET = app2
main.cpp
#include <qapplication.h>
#include "mainWindow.h"
int main( int ac, char ** av )
{
QApplication a( ac, av );
MainWindow * mw = new MainWindow( "MainWindow" );
a.setMainWidget( mw );
mw->show();
a.exec();
return 0;
}
mainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <qmainwindow.h>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow( const char * name );
public slots:
void search();
};
#endif // MAINWINDOW_H
mainWindow.cpp
#include <qlabel.h>
#include <qlayout.h>
#include <qpopupmenu.h>
#include <qmenubar.h>
#include <qapplication.h>
#include "mainWindow.h"
MainWindow::MainWindow( const char * name )
: QMainWindow( 0L, name )
{
setCaption("An application");
// Main Widget
QLabel * mainWidget = new QLabel("A main widget!", this );
setCentralWidget( mainWidget );
mainWidget->setAlignment( AlignVCenter | AlignHCenter );
// Menu bar
QPopupMenu* file = new QPopupMenu( this );
file->insertItem("E&xit", qApp, SLOT( quit() ) );
menuBar()->insertItem( "&File", file );
QPopupMenu* edit = new QPopupMenu( this );
edit->insertItem("Search", this, SLOT( search() ) );
menuBar()->insertItem( "&Edit", edit );
// Status bar
statusBar();
}
void MainWindow::search()
{
qDebug("search!");
}
testSearchDialog.h
#ifndef TESTSEARCHDIALOG_H
#define TESTSEARCHDIALOG_H
#include "TestCase.h"
#include "TestSuite.h"
#include "TestCaller.h"
class TestSearchDialog : public TestCase
{
public:
TestSearchDialog(const char * name )
: TestCase(name)
{}
void setUp () {}
void tearDown() {}
static Test *suite ()
{
TestSuite *testSuite = new TestSuite ("Search Dialog");
return testSuite;
}
};
#endif // TESTSEARCHDIALOG_H
testSearchDialog.cpp:
#include "testSearchDialog.h"
example2.pro
TEMPLATE = app
CONFIG = qt warn_on debug
unix:LIBS = -L../qcppunit -lqcppunit
INCLUDEPATH = ../qcppunit ../qcppunit/testlib
HEADERS = \
mainWindow.h \
testSearchDialog.h
SOURCES = \
main.cpp \
mainWindow.cpp \
testSearchDialog.cpp
TARGET = app2
mainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <qmainwindow.h>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow( const char * name );
public slots:
void search();
void runTestDialog();
};
#endif // MAINWINDOW_H
new mainWindow.cpp
#include <qlabel.h>
#include <qlayout.h>
#include <qpopupmenu.h>
#include <qmenubar.h>
#include <qapplication.h>
#include "mainWindow.h"
#include "guiRunner.h"
#include "testSearchDialog.h"
MainWindow::MainWindow( const char * name )
: QMainWindow( 0L, name )
{
setCaption("An application");
// Main Widget
QLabel * mainWidget = new QLabel("A main widget!", this );
setCentralWidget( mainWidget );
mainWidget->setAlignment( AlignVCenter | AlignHCenter );
// Menu bar
QPopupMenu* file = new QPopupMenu( this );
file->insertItem("E&xit", qApp, SLOT( quit() ) );
menuBar()->insertItem( "&File", file );
QPopupMenu* edit = new QPopupMenu( this );
edit->insertItem("Search", this, SLOT( search() ) );
menuBar()->insertItem( "&Edit", edit );
QPopupMenu* test = new QPopupMenu( this );
test->insertItem("test", this, SLOT( runTestDialog() ) );
menuBar()->insertItem( "&Test", test );
// Status bar
statusBar();
}
void MainWindow::search()
{
qDebug("search!");
}
void MainWindow::runTestDialog()
{
GuiTestRunner * runner = new GuiTestRunner;
// add your test suites here
Test * suite;
suite = TestSearchDialog::suite();
runner->addTest( suite->toString(), suite );
runner->show();
}
testSearchDialog.cpp
void TestSearchDialog::testCreate()
{
SearchDialog * sd = new SearchDialog();
sd->exec();
sd->setCaption("Search Dialog");
delete sd;
}
searchDialog.h:
#ifndef SEARCHDIALOG_H
#define SEARCHDIALOG_H
#include <qdialog.h>
class SearchDialog : public QDialog
{
public:
SearchDialog();
};
#endif // SEARCHDIALOG_H
searchDialog.cpp
#include "searchDialog.h"
SearchDialog::SearchDialog()
: QDialog(0, "Search Dialog", true )
{
}
Now, when we launch the test dialog, the progress bar goes from 0% to 100% and is green. This means that all tests were successfully run. Our test suite item's color is green, which means all its tests were successful. It reads "1/1" : 1 test successful on a total of 1 test. Cool, everything works.
testSearchDialog.h
#ifndef TESTSEARCHDIALOG_H
#define TESTSEARCHDIALOG_H
#include "TestCase.h"
#include "TestSuite.h"
#include "TestCaller.h"
class TestSearchDialog : public TestCase
{
public:
TestSearchDialog(const char * name )
: TestCase(name)
{}
void setUp () {}
void tearDown() {}
static Test *suite ()
{
TestSuite *testSuite = new TestSuite ("Search Dialog");
testSuite->addTest( new TestCaller<TestSearchDialog> ("testCreate", &TestSearchDialog::testCreate ));
return testSuite;
}
protected:
// My tests
void testCreate();
};
#endif // TESTSEARCHDIALOG_H
testSearchDialog.h extract
class TestSearchDialog : public TestCase
{
public:
TestSearchDialog(const char * name )
: TestCase(name)
{}
void setUp ();
void tearDown();
static Test *suite ()
{
TestSuite *testSuite = new TestSuite ("Search Dialog");
testSuite->addTest( new TestCaller<TestSearchDialog> ("testCreate", &TestSearchDialog::testCreate ));
testSuite->addTest( new TestCaller<TestSearchDialog> ("testWidgetPresent", &TestSearchDialog::testWidgetPresent ));
return testSuite;
}
protected:
// My tests
void testCreate();
void testWidgetPresent();
SearchDialog * _sd;
};
void TestSearchDialog::setUp()
{
_sd = new SearchDialog();
_sd->setCaption( "Search dialog");
_sd->show();
}
void TestSearchDialog::tearDown()
{
QTime t;
t.start();
while( t.elapsed() < 1000 ) {
qApp->processEvents();
}
delete _sd;
_sd = 0;
}
void TestSearchDialog::testCreate()
{
SearchDialog * sd = new SearchDialog();
sd->setCaption( "Search dialog");
sd->show();
delete sd;
}
void TestSearchDialog::testWidgetPresent()
{
check( _sd->_queryLabel != 0l );
check( _sd->_queryText != 0l );
check( _sd->_buttonSearch != 0l );
check( _sd->_resultWidget != 0l );
}
It compiles, it runs. We launch the test dialog. This times, the progress bar is green until it gets to 50%. At this time, a window appears on the screen and disappears. The the progress bar turns red, a new window appears and disappears.
searchDialog.h
#ifndef SEARCHDIALOG_H
#define SEARCHDIALOG_H
#include <qdialog.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qlistview.h>
class TestSearchDialog;
class SearchDialog : public QDialog
{
public:
SearchDialog();
protected:
QLabel * _queryLabel;
QLineEdit * _queryText;
QPushButton * _buttonSearch;
QListView * _resultWidget;
friend TestSearchDialog;
};
#endif // SEARCHDIALOG_H
testWidgetPresent testSearchDialog.cpp 40 "_sd->_queryLabel != 0L"the test testWidgetPresent failed, in the file testSearchDialog.cpp, line 40 and the failure cause is "_sd->queryLabel != 0L" is not true.
Compile, run. The test passes and you see the dialog popping up with the new items we have just added.
searchDialog.cpp extract
SearchDialog::SearchDialog()
: QDialog(0, "Search Dialog", false)
{
QVBoxLayout * vly = new QVBoxLayout( this );
vly->setAutoAdd( true );
QHBox * hbox = new QHBox( this );
_queryLabel = new QLabel( "Query : ", hbox );
_queryText = new QLineEdit( hbox );
_buttonSearch = new QPushButton( "Search", hbox );
_resultWidget = new QListView( this );
}
testSearchDialog.cpp extract
void TestSearchDialog::testWidgetPresent()
{
check( _sd->_queryLabel != 0l );
check( _sd->_queryLabel->text().isEmpty() == false );
check( _sd->_queryText != 0l );
check( _sd->_queryText->text().isEmpty() == true );
check( _sd->_buttonSearch != 0l );
check( _sd->_buttonSearch->text().isEmpty() == false );
check( _sd->_resultWidget != 0l );
check( _sd->_resultWidget->childCount() == 0 );
}
A query is built from a text field. The Searcher object returns a result out of a query. The result contain 0 to many documents, which have a title, an author and a year of publication.
searchInterface.h
#ifndef SEARCHINTERFACE_H
#define SEARCHINTERFACE_H
class Query
{
public:
Query( const char * ) {}
virtual const char * getValue()=0;
};
class Document
{
public:
virtual const char * getTitle()=0;
virtual const char * getAuthor()=0;
virtual const char * getYear()=0;
};
class Result
{
public:
virtual int getCount()=0;
virtual Document * getItem( int i )=0;
};
class Searcher
{
public:
virtual Result * find( Query * q )=0;
};
#endif // SEARCHINTERFACE_H
testSearchBackend.h
#ifndef TESTSEARCHBACKEND_H
#define TESTSEARCHBACKEND_H
#include "TestCase.h"
#include "TestSuite.h"
#include "TestCaller.h"
class TestSearchBackend : public TestCase
{
public:
TestSearchBackend(const char * name )
: TestCase(name)
{}
static Test *suite ()
{
TestSuite *testSuite = new TestSuite ("Search Backend");
testSuite->addTest( new TestCaller<TestSearchBackend> ("testCreate", &TestSearchBackend::testCreate ));
return testSuite;
}
protected:
// My tests
void testCreate();
};
To make it compile, we add our FakeBackend classes:
testSearchBackend.cpp
void TestSearchBackend::testCreate()
{
FakeSearcher * s = new FakeSearcher();
FakeQuery * q = new FakeQuery("");
FakeResult * r = new FakeResult();
FakeDocument * d = new FakeDocument(0);
s = 0L;
q = 0L;
r = 0L;
d = 0L;
}
FakeBackend.h
#ifndef SEARCHBACKEND_H
#define SEARCHBACKEND_H
#include "searchInterface.h"
class FakeQuery : virtual public Query
{
public:
FakeQuery( const char *s ) : Query(s) {}
virtual const char * getValue() { return 0L; }
};
class FakeDocument : public Document
{
public:
FakeDocument(int) {}
virtual const char * getTitle() { return 0L; }
virtual const char * getAuthor() { return 0L; }
virtual const char * getYear() { return 0L; }
};
class FakeResult : public Result
{
public:
virtual int getCount() { return 0L; }
virtual Document * getItem( int i ) { return 0L; }
};
class FakeSearcher : virtual public Searcher
{
public:
FakeSearcher();
virtual Result * find( Query * q );
};
#endif // SEARCHBACKEND_H
mainWindow.cpp extract
void MainWindow::runTestDialog()
{
GuiTestRunner * runner = new GuiTestRunner;
// add your test suites here
Test * suite;
suite = TestSearchDialog::suite();
runner->addTest( suite->toString(), suite );
suite = TestSearchBackend::suite();
runner->addTest( suite->toString(), suite );
runner->show();
}
Note that since the function returning our test suite is inline, the new test won't appear until we recompile mainWindow.cpp (where the real code is). This is the cost for having the test suite construction and the test list at the same place.
testSearchBackend.cpp extract
void TestSearchBackend::testBackend()
{
qDebug("testbackend");
Query * q = new FakeQuery("1");
checkEquals( q->getValue(), "1" );
Document * d = new FakeDocument(1);
checkEquals( d->getAuthor(), "a1" );
checkEquals( d->getYear(), "y1" );
Result * r = new FakeResult( 2 );
checkEquals( r->getCount(), 2 );
checkEquals( r->getItem(1)->getAuthor(), "a1" );
checkEquals( r->getItem(2)->getYear(), "y2" );
Searcher * s = new FakeSearcher();
r = s->find( new FakeQuery( "2" ) );
check( r != 0L );
checkEquals( r->getCount(), 2 );
checkEquals( r->getItem(1)->getAuthor(), "a1" );
checkEquals( r->getItem(2)->getYear(), "y2" );
}
main.cpp
#include <qapplication.h>
#include "mainWindow.h"
#include "guiRunner.h"
#include "testSearchDialog.h"
#include "testSearchBackend.h"
int main( int ac, char ** av )
{
QApplication a( ac, av );
/*
MainWindow * mw = new MainWindow( "MainWindow" );
a.setMainWidget( mw );
mw->show();
*/
GuiTestRunner * runner = new GuiTestRunner;
// add your test suites here
Test * suite;
suite = TestSearchDialog::suite();
runner->addTest( suite->toString(), suite );
suite = TestSearchBackend::suite();
runner->addTest( suite->toString(), suite );
runner->show();
a.exec();
return 0;
}
searchBackend.h
class FakeQuery : virtual public Query
{
public:
FakeQuery( const char *s ) : Query(s), _value(s) {}
virtual const char * getValue() { return _value.latin1(); }
protected:
QString _value;
};
class FakeDocument : public Document
{
public:
FakeDocument(int i);
virtual const char * getAuthor() { return _author; }
virtual const char * getYear() { return _year; }
protected:
char _author[10];
char _year[10];
};
class FakeResult : public Result
{
public:
FakeResult( int i=0 ) : _count(i) {}
virtual int getCount() { return _count; }
virtual Document * getItem( int i ) { return new FakeDocument(i); }
protected:
int _count;
};
class FakeSearcher : virtual public Searcher
{
public:
virtual Result * find( Query * q );
};
searchBackend.cpp:
FakeDocument::FakeDocument(int i)
{
strcpy( _author, "a0" );
_author[1] = '0' + i;
strcpy( _year, "y0" );
_year[1] = '0' + i;
}
Result * FakeSearcher::find( Query * q)
{
if (q == 0L) return 0L;
return new FakeResult( atoi( q->getValue() ) );
}
testSearchDialog.cpp extract
void TestSearchDialog::testDialogSearcher()
{
check( _sd->getSearcher() == 0L );
Searcher * s = new FakeSearcher();
_sd->setSearcher( s );
check( _sd->getSearcher() == s );
Searcher * s2 = new FakeSearcher();
check( _sd->getSearcher() == s2 );
}
searchDialog.h
class SearchDialog : public QDialog
{
public:
SearchDialog();
void setSearcher( Searcher * s ) { _searcher = s; }
Searcher * getSearcher() { return _searcher; }
protected:
QLabel * _queryLabel;
QLineEdit * _queryText;
QPushButton * _buttonSearch;
QListView * _resultWidget;
Searcher * _searcher;
friend TestSearchDialog;
};
Now, the test pass.
searchDialog.cpp
SearchDialog::SearchDialog()
: QDialog(0, "Search Dialog", false)
{
_searcher = 0L;
...
testSearchDialog.cpp extract
void TestSearchDialog::testQuery1()
{
_sd->_queryText->setText("1");
_sd->_buttonSearch->animateClick();
checkEquals( _sd->_resultWidget->childCount(), 1 );
}
searchDialog.cpp extract
SearchDialog::SearchDialog()
: QDialog(0, "Search Dialog", false)
{
_searcher = 0L;
QVBoxLayout * vly = new QVBoxLayout( this );
vly->setAutoAdd( true );
QHBox * hbox = new QHBox( this );
_queryLabel = new QLabel( "Query : ", hbox );
_queryText = new QLineEdit( hbox );
_buttonSearch = new QPushButton( "Search", hbox );
_resultWidget = new QListView( this );
_resultWidget->addColumn( "Title" );
_resultWidget->addColumn( "Author" );
_resultWidget->addColumn( "Year" );
connect( _buttonSearch, SIGNAL(clicked()), SLOT(performSearch()) );
}
void SearchDialog::performSearch()
{
if (_searcher == 0L) {
qDebug("SearchDialog::performSearch() - No searcher set!" );
return;
}
FakeQuery * q = new FakeQuery( _queryText->text().latin1() );
Result * r = _searcher->find( q );
for( int i=0; i < r->getCount(); i++) {
Document * d = r->getItem(i);
new QListViewItem( _resultWidget, d->getTitle(), d->getAuthor(),
d->getYear() );
}
}
testSearchDialog.cpp extract
void TestSearchDialog::testQuery1()
{
_sd->setSearcher( new FakeSearcher() );
_sd->_queryText->setText("1");
_sd->_buttonSearch->animateClick();
QTime t;
t.start();
while( t.elapsed() < 1000 ) {
qApp->processEvents();
}
checkEquals( _sd->_resultWidget->childCount(), 1 );
}
testSearchDialog.cpp extract
void TestSearchDialog::testQuery1()
{
_sd->setSearcher( new FakeSearcher() );
_sd->_queryText->setText("1");
_sd->_buttonSearch->animateClick();
QTime t;
t.start();
while( t.elapsed() < 1000 ) {
qApp->processEvents();
}
checkEquals( _sd->_resultWidget->childCount(), 1 );
QListViewItem * item;
item = _sd->_resultWidget->firstChild();
checkEquals( item->text(0), "t1" );
checkEquals( item->text(1), "a1" );
checkEquals( item->text(2), "y1" );
}
The test runs perfectely right from the start. Good.
testSearchDialog.cpp extract
void TestSearchDialog::testQuery0()
{
_sd->setSearcher( new FakeSearcher() );
_sd->_queryText->setText("0");
_sd->_buttonSearch->animateClick();
QTime t;
t.start();
while( t.elapsed() < 1000 ) {
qApp->processEvents();
}
checkEquals( _sd->_resultWidget->childCount(), 0 );
}
testSearchDialog.cpp extract
void TestSearchDialog::testQueryMany()
{
_sd->setSearcher( new FakeSearcher() );
_sd->_queryText->setText("5");
_sd->_buttonSearch->animateClick();
QTime t;
t.start();
while( t.elapsed() < 1000 ) {
qApp->processEvents();
}
checkEquals( _sd->_resultWidget->childCount(), 5 );
QListViewItem * item;
item = _sd->_resultWidget->firstChild();
checkEquals( item->text(0), "t1" );
checkEquals( item->text(1), "a1" );
checkEquals( item->text(2), "y1" );
item = item->nextSibling();
checkEquals( item->text(0), "t2" );
item = item->nextSibling();
checkEquals( item->text(1), "a3" );
item = item->nextSibling();
checkEquals( item->text(2), "y4" );
item = item->nextSibling();
checkEquals( item->text(0), "t5" );
item = item->nextSibling();
check( item == 0L );
}
It doesn't work, because we didn't clean the result widget when performing a new search.
testSearchDialog.cpp extract
void TestSearchDialog::testMultipleQuery()
{
testQueryMany();
testQuery1();
}
searchDialog.cpp extract
void SearchDialog::performSearch()
{
if (_searcher == 0L) {
qDebug("SearchDialog::performSearch() - No searcher set!" );
return;
}
_resultWidget->clear();
FakeQuery * q = new FakeQuery( _queryText->text().latin1() );
Result * r = _searcher->find( q );
for( int i=0; i < r->getCount(); i++) {
Document * d = r->getItem(i+1);
new QListViewItem( _resultWidget, d->getTitle(), d->getAuthor(),
d->getYear() );
}
delete q;
delete r;
}