QSignalSpy — мощный класс из модуля QtTest, который используется для отслеживания сигналов во время юнит-тестирования. Он позволяет проверить, был ли сигнал отправлен, сколько раз, с какими аргументами и в каком порядке.
Назначение
Когда вы пишете юнит-тесты в Qt, часто возникает необходимость убедиться, что сигнал был сгенерирован, например:
- пользователь нажал кнопку;
- завершилась асинхронная операция;
- произошла ошибка;
- объект изменил состояние.
В таких случаях QSignalSpy заменяет ручное подключение сигналов к слотам и анализирует информацию о них автоматически.
Подключение
#include <QSignalSpy> #include <QtTest>
Также потребуется:
QT += testlib
Простой пример
Допустим, у нас есть класс:
class MyObject : public QObject {
Q_OBJECT
public:
void doSomething() {
emit finished(42);
}
signals:
void finished(int value);
};
Теперь напишем тест с использованием QSignalSpy:
void testSignal() {
MyObject obj;
QSignalSpy spy(&obj, SIGNAL(finished(int)));
obj.doSomething();
QCOMPARE(spy.count(), 1); // сигнал должен быть вызван один раз
QList<QVariant> arguments = spy.takeFirst();
QCOMPARE(arguments.at(0).toInt(), 42); // проверка переданного аргумента
}
Методы класса QSignalSpy
| Метод | Описание |
|---|---|
spy.count() | Количество вызовов сигнала |
spy.wait(ms) | Ожидание сигнала (удобно для асинхронных операций) |
spy.takeFirst() | Получить список аргументов первого вызова |
spy.at(index) | Получить список аргументов по индексу |
spy.isValid() | Проверка, правильно ли создан шпион |
Пример с асинхронностью
QSignalSpy spy(&object, &SomeClass::finished); // запускаем асинхронную операцию object.startWork(); // ждём до 2 секунд, пока не будет вызван сигнал QVERIFY(spy.wait(2000)); QCOMPARE(spy.count(), 1);
Поддержка перегруженных сигналов
Если сигнал перегружен (имеет несколько вариантов), используйте функциональный указатель:
QSignalSpy spy(&object, SIGNAL(signalName(Type)));
Обработка аргументов
QList<QVariant> args = spy.at(0); QString name = args.at(0).toString(); int id = args.at(1).toInt();
Практика: пример с QPushButton
QPushButton button; QSignalSpy clickedSpy(&button, &QPushButton::clicked); QTest::mouseClick(&button, Qt::LeftButton); QCOMPARE(clickedSpy.count(), 1);
Использование в рамках QTest
class TestMyClass : public QObject {
Q_OBJECT
private slots:
void testFinishedSignal();
};
void TestMyClass::testFinishedSignal() {
MyObject obj;
QSignalSpy spy(&obj, SIGNAL(finished(int)));
obj.doSomething();
QCOMPARE(spy.count(), 1);
QList<QVariant> args = spy.takeFirst();
QCOMPARE(args.at(0).toInt(), 42);
}
Потенциальные недостатки
QSignalSpyработает только в пределах одного потока, где расположен объект.- В случае с асинхронными сигналами может потребоваться
QTRY_COMPAREилиwait(). - Проверка типов аргументов основана на
QVariant, что может привести к неявным приведением.
Заключение
QSignalSpy — незаменимый инструмент для тестирования событийной архитектуры в Qt. Он помогает:
- Проверить, вызываются ли сигналы;
- Проверить передаваемые параметры;
- Проверить асинхронные реакции и события в GUI.
