Единственный инструмент, который я нашел - QTestLib. К сожалению, его описание весьма скромное:
К сожалению, официальная документация описывает сферический QString в вакууме, в который поместили "Hello world!". Разумеется в этом случае мне совсем не хотелось бросаться в омут с головой и резать по живому. Поэтому для экспериментов придумал простенькое приложение "Подсчет площади квадрата", о котором и пойдет речь дальше.
Как и полагается, начал я с теста.
#include <QtTest/QtTest> #include "ui_SqAreaForm.h" class TestGui: public QObject { Q_OBJECT private slots: void NormalAreaCalc_data() { QTest::addColumn<QTestEventList>("events"); QTest::addColumn<QString>("expected"); QTestEventList list1; list1.addKeyClick('0'); QTest::newRow("zero") << list1 << "0"; QTestEventList list2; list2.addKeyClicks("10"); QTest::newRow("sq_10") << list2 << "100"; } void NormalAreaCalc() { QFETCH(QTestEventList, events); QFETCH(QString, expected); QWidget wdg; Ui_SqAreaForm frm; frm.setupUi(&wdg); events.simulate(frm.side); QCOMPARE(frm.area->text(), expected); } }; QTEST_MAIN(TestGui) #include "test.moc"Т.е. я планирую создать в дизайнере ui, в котором есть поле ввода side и QLabel area, и ожидаю, что площадь для квадрата с нулевой стороной - ноль, а для 10 - 100. Пока все просто и практически по туториалу. Теперь добавим класс, который будет управлять этим самим ui.
#include <QWidget> class Ui_SqAreaForm; class SqAreaForm : public QWidget { Q_OBJECT public: SqAreaForm(); ~SqAreaForm(); #ifdef _TESTING_ Ui_SqAreaForm* GetUi(); #endif private: Ui_SqAreaForm* ui; };Помимо типичного кода я добавил еще один метод специально для тестирования. Конечно, неприятно вносить изменения в код ради тестирования, но это изменение минимально и не влияет на работу приложения. Можно обойтись и без добавления этого метода, но тогда придется получать доступ к виджетам через QApplication::allWidgets(), что во много раз сложнее. Существует еще один вариант, когда наша форма предоставляет геттеры и сеттеры, но, как минимум, главному окну такая функциональность точно не нужна.
А теперь самое интересное добавляем слот для реакции на изменение поля side:
void SqAreaForm::OnSqSideChanged(const QString& newSide) { int side = newSide.toInt(); int area = side*side; ui->area->setText(QString::number(area)); }Что ж - тесты пройдены и это не может не радовать. Но что делать с ui, который мы не можем вернуть через GetUi? Например, диалоговые окна или окна с сообщениями. Для этого поменяем требования к нашему приложению - пусть площадь рассчитывается после нажатия кнопки и результат появляется во всплывающем окне. В этом случае протестировать работу приложения будет немного сложнее:
#include <QtTest/QtTest> #include "ui_SqAreaForm.h" #include "SqAreaForm.h" #include <QApplication> #include <QMessageBox> #include <QTimer> class TestGui: public QObject { Q_OBJECT private slots: void initTestCase() { msgBoxProcessTimer.setInterval(1000); msgBoxProcessTimer.setSingleShot(true); QVERIFY(QObject::connect(&msgBoxProcessTimer, SIGNAL(timeout()), this, SLOT(MsgBoxProcess()))); } void NormalAreaCalc_data() { QTest::addColumn<QTestEventList>("events"); QTest::addColumn<QString>("expected"); QTestEventList list1; list1.addKeyClick('0'); QTest::newRow("zero") << list1 << "Area of the sqare with side 0 is 0"; QTestEventList list2; list2.addKeyClicks("10"); QTest::newRow("sq_10") << list2 << "Area of the sqare with side 10 is 100"; } void NormalAreaCalc() { QFETCH(QTestEventList, events); QFETCH(QString, expected); SqAreaForm frm; Ui_SqAreaForm* ui = frm.GetUi(); msgBoxProcessTimer.start(); events.simulate(ui->side); QTest::mouseClick(ui->calc, Qt::LeftButton); QCOMPARE(msgBoxMessage, expected); } void MsgBoxProcess() { QMessageBox* msgBox = dynamic_cast<QMessageBox*>(QApplication::activeModalWidget()); if (msgBox != 0) { msgBoxMessage = msgBox->text(); msgBox->close(); } } private: QTimer msgBoxProcessTimer; QString msgBoxMessage; }; QTEST_MAIN(TestGui) #include "test.moc"Идея теста очень проста: т.к. QDialog::exec() блокирует поток выполнения, нам необходимо взвести таймер, чтобы через 1 секунду обработать уже появившееся окно. Решение, на мой взгляд, не самое удачное, т.к. каждый подобный тест занимает не меньше 1 секунды. Можно поступить более мудро и проверять появление модального окна, скажем, каждые 10мс. Для этого меняем интервал таймера и делаем его не одноразовым(setSingleShot(false)).
С помощью двух описанных выше методик можно вполне сносно протестировать типичные сценарии поведения GUI приложений, написанных на Qt.
Исходники примеров тут.
Долго пыталась разобраться с тестами GUI. Спасибо, что потрудились поделиться наработками - с "живыми" примерами разобраться намного проще.
ОтветитьУдалить