gpt4 book ai didi

qt - 如何测试 QStateMachine?

转载 作者:行者123 更新时间:2023-12-01 15:22:51 27 4
gpt4 key购买 nike

我对如何测试 QStateMachine 有点困惑。我有一个组织良好的项目,一侧是源代码,另一侧是测试代码。

标题

class Foo
{
signals:
void sigGoToStateOne();
void sigGoToStateTwo();
void sigGoToStateThree();

private:
QStateMachine *stateMachine;
QState *state1;
QState *state2;

void initStateMachine();
}

在源文件中

Foo::initStateMachine()
{
// constructors
state1->addTransition(this,SIGNAL(sigGoToStateTwo()),this->state2);
state2->addTransition(this,SIGNAL(sigGoToStateOne()),this->state1);
}

我想知道是否有一种漂亮的方法来测试我的 stateMachine 是否正确。换句话说,如果我在那里发出 sigGoToStateThree() 等,我的状态机将如何 react 。

我看到的解决方案:1 - 获取 stateMachine(以及最终所有其他状态)的地址并对其进行测试(但我不知道如何)2 - 从测试文件模拟信号 (sigGoToStateX())(同样,不知道是否可以在其他类中发出我的类 Foo 的信号)

我的独特需求是我不想修改我的源文件的核心。

提前致谢。

最佳答案

在 Qt 5 中,信号始终是公共(public)方法。为了使您的代码与 Qt 4 兼容,您可以像这样显式公开信号:

class Foo {
public:
Q_SIGNAL void sigGoToStateOne();
...
}

或者,您可以保持任意信号可见性,并声明一个友元测试类:

class Foo {
friend class FooTest;
...
}

最后,您可以创建一个测试项目,您可以在其中使用 Qt 的测试框架来测试 Foo 类的行为。下面的代码适用于 Qt 4 和 Qt 5。

// main.cpp
#include <QCoreApplication>
#include <QStateMachine>
#include <QEventLoop>
#include <QtTest>
#include <QTimer>

class Waiter {
QTimer m_timer;
public:
Waiter() {}
Waiter(QObject * obj, const char * signal) {
m_timer.connect(obj, signal, SIGNAL(timeout()));
}
void stop() {
m_timer.stop();
QMetaObject::invokeMethod(&m_timer, "timeout");
}
void wait(int timeout = 5000) {
QEventLoop loop;
m_timer.start(timeout);
loop.connect(&m_timer, SIGNAL(timeout()), SLOT(quit()));
loop.exec();
}
};

class SignalWaiter : public QObject, public Waiter {
Q_OBJECT
int m_count;
Q_SLOT void triggered() {
++ m_count;
stop();
}
public:
SignalWaiter(QObject * obj, const char * signal) : m_count(0) {
connect(obj, signal, SLOT(triggered()), Qt::QueuedConnection);
}
int count() const { return m_count; }
};

#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
typedef QSignalSpy SignalSpy;
#else
class SignalSpy : public QSignalSpy, public Waiter {
public:
SignalSpy(QObject * obj, const char * signal) :
QSignalSpy(obj, signal), Waiter(obj, signal) {}
};
#endif

class Foo : public QObject {
Q_OBJECT
friend class FooTest;
QStateMachine m_stateMachine;
QState m_state1;
QState m_state2;
Q_SIGNAL void sigGoToStateOne();
Q_SIGNAL void sigGoToStateTwo();
public:
explicit Foo(QObject * parent = 0) :
QObject(parent),
m_state1(&m_stateMachine),
m_state2(&m_stateMachine)
{
m_stateMachine.setInitialState(&m_state1);
m_state1.addTransition(this, SIGNAL(sigGoToStateTwo()), &m_state2);
m_state2.addTransition(this, SIGNAL(sigGoToStateOne()), &m_state1);
}
Q_SLOT void start() {
m_stateMachine.start();
}
};

class FooTest : public QObject {
Q_OBJECT
void call(QObject * obj, const char * method) {
QMetaObject::invokeMethod(obj, method, Qt::QueuedConnection);
}
Q_SLOT void test1() {
// Uses QSignalSpy
Foo foo;
SignalSpy state1(&foo.m_state1, SIGNAL(entered()));
SignalSpy state2(&foo.m_state2, SIGNAL(entered()));
call(&foo, "start");
state1.wait();
QCOMPARE(state1.count(), 1);
call(&foo, "sigGoToStateTwo");
state2.wait();
QCOMPARE(state2.count(), 1);
call(&foo, "sigGoToStateOne");
state1.wait();
QCOMPARE(state1.count(), 2);
}

Q_SLOT void test2() {
// Uses SignalWaiter
Foo foo;
SignalWaiter state1(&foo.m_state1, SIGNAL(entered()));
SignalWaiter state2(&foo.m_state2, SIGNAL(entered()));
foo.start();
state1.wait();
QCOMPARE(state1.count(), 1);
emit foo.sigGoToStateTwo();
state2.wait();
QCOMPARE(state2.count(), 1);
emit foo.sigGoToStateOne();
state1.wait();
QCOMPARE(state1.count(), 2);
}
};

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
FooTest test;
QTest::qExec(&test, a.arguments());
QMetaObject::invokeMethod(&a, "quit", Qt::QueuedConnection);
return a.exec();
}

#include "main.moc"

我强制所有信号调用从事件循环中完成,这样事件转换只会在事件循环运行时发生。这使得测试代码在每次转换后统一等待。否则,第二个 wait 会超时:

Q_SLOT void test1() {
SignalSpy state1(&m_foo.m_state1, SIGNAL(entered()));
SignalSpy state2(&m_foo.m_state2, SIGNAL(entered()));
m_foo.start();
state1.wait();
QCOMPARE(state1.count(), 1);
emit m_foo.sigGoToStateTwo(); // The state2.entered() signal is emitted here.
state2.wait(); // But we wait for it here, and this wait will time out.
QCOMPARE(state2.count(), 1); // But of course the count will match.
emit m_foo.sigGoToStateOne();
state1.wait(); // This would timeout as well.
QCOMPARE(state1.count(), 2);
}

这可以在不使用显式排队调用的情况下通过使用内部使用排队连接的信号 spy 类来解决。

关于qt - 如何测试 QStateMachine?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24148670/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com