QTimer 超时不会在单元测试中触发
QTimer timout doesnt trigger in unit testing
我正在尝试为我命名为 Counter 的 class 创建一个单元测试。这样 class 应该每 0.1 秒减少它的值 "count" ,所以我在 class 构造函数中连接了该方法。在原来的程序中一切似乎都工作得很好,但是当我尝试 运行 单元测试器时,它似乎没有发生连接或者 QTimer 根本没有发送超时信号。
gitHub link: https://github.com/allocro/TimerLFdP/tree/master/testCounter
Counter::Counter(QLineEdit *editSec, QLineEdit *editMin, QObject *parent) :
QObject(parent)
{
timer= new QTimer(this);
[...]
connect(timer, &QTimer::timeout, this, &Counter::decCount);
}
编辑:K,我将按照要求将其他代码部分放入此处。
在前面的代码中,这里是我要测试的class的构造函数,decCount()所做的无非是:
void Counter::decCount(){
if (count>0)
count--;
else
timer->stop();
int countsec = count % 600;
int countmin = (count - countsec)/600;
QString secOut = QString::number(countsec/10) + "."
+QString::number(countsec%10);
emit showCountMin(countmin);
emit showCountSec(secOut);
}
以上信号与单元测试代码无关,它们在完整程序中使用。
现在,在tst_testCounter.cpp中,据我了解,是classic main的测试单元版本,我得到了
testCounter::testCounter() : QObject ()
{ int i;
editSec= new QLineEdit();
editMin= new QLineEdit();
counter= new Counter(editSec, editMin);
for(i=0; i<=10; i++){
int randsec= rand() %60;
int randmin= rand() %60;
randsec=3;
randmin=0; //To test the tester faster
QString randsecString= QString::number(randsec);
QString randminString= QString::number(randmin);
editSec->setText(randsecString);
editMin->setText(randminString);
counter->set();//those are to input, they work fine, I checked
std::cout << "Starting the Timer at " << (counter->count)/10 <<
"sec" <<std::endl;
counter->start(); //{timer->start();}
while(counter->count>0){
std::cout <<counter->count <<std::endl;
}
auto end= std::chrono::system_clock::now();
counter->stop();
auto check= std::chrono::duration_cast<std::chrono::seconds>(end -
start);
int checkInt= check.count();
if(checkInt==randsec+(randmin*60)){
std::cout << "Timer matches" <<std::endl;
}else{
std::cout << "Timer doesnt match" <<std::endl;
std::cout << "Sec counted: " << (counter->count)/10 <<std::endl;
std::cout << "Sec passed: " << checkInt <<std::endl;
break;
}
}
}
显然 .cpp 以
结尾
QTEST_MAIN(testCounter)
#include "tst_testcounter.moc"
首先要记住的是QTimer
不是精确的,所以按秒的顺序检查会出问题,更好的测试验证以毫秒为单位的时间差小于一定的价值。
另一方面,指令:
while (counter-> count> 0) {
std::cout << counter-> count << std::endl;
}
您没有让事件循环工作,因此 QTimer 或信号可以工作。
你应该使用的是QCoreApplication::processEvents()
:
while(counter.count>0){
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
}
也建议测试的元素定义在方法内部,测试不在构造函数中给出,而是在槽中给出。
综合以上,并进行其他改进,得到:
counter.h
#ifndef COUNTER_H
#define COUNTER_H
#include <QObject>
class QTimer;
class QLineEdit;
class Counter : public QObject
{
Q_OBJECT
public:
explicit Counter(QLineEdit *setterSec, QLineEdit *setterMin, QObject *parent = nullptr);
QTimer *timer;
QLineEdit *setterSec;
QLineEdit *setterMin;
int count;
signals:
void showCountSec(const QString &count);
void showCountMin(int count);
public slots:
void decCount();
void start();
void stop();
void set();
};
#endif // COUNTER_H
counter.cpp
#include "counter.h"
#include <QTimer>
#include <QIntValidator>
#include <QLineEdit>
Counter::Counter(QLineEdit *editSec, QLineEdit *editMin, QObject *parent) :
QObject(parent),
timer(new QTimer(this)),
setterSec(editSec),
setterMin(editMin),
count(0)
{
setterSec->setValidator(new QIntValidator(0, 59, this));
setterMin->setValidator(new QIntValidator(0, 59, this));
connect(timer, &QTimer::timeout, this, &Counter::decCount);
}
void Counter::start(){
timer->start(100);
}
void Counter::stop(){
timer->stop();
}
void Counter::set(){
timer->stop();
count = setterSec->text().toInt()*10 + setterMin->text().toInt()*600;
int countsec = count % 600;
int countmin = (count - countsec)/600;
QString secOut = QString::number(countsec/10) + "." +QString::number(countsec%10);
emit showCountMin(countmin);
emit showCountSec(secOut);
}
void Counter::decCount(){
if (count > 0)
count--;
else
timer->stop();
int countsec = count % 600;
int countmin = (count - countsec)/600;
QString secOut = QString::number(countsec/10) + "." +QString::number(countsec%10);
emit showCountMin(countmin);
emit showCountSec(secOut);
}
tst_counter.h
#include <QtTest>
#include "counter.h"
#include <QLineEdit>
#include <iostream>
#include <cmath>
#include <QDebug>
// add necessary includes here
class tst_Counter : public QObject
{
Q_OBJECT
public:
tst_Counter();
~tst_Counter();
private slots:
void initTestCD();
};
tst_Counter::tst_Counter() : QObject ()
{
}
tst_Counter::~tst_Counter()
{
}
void tst_Counter::initTestCD(){
QLineEdit editSec;
QLineEdit editMin;
Counter counter(&editSec, &editMin);
const int epsilon = 50; // ms
for(int i=0; i<=10; i++){
int randsec= rand() %60;
int randmin= rand() %60;
randsec =3;
randmin =0; //To test the tester faster
QString randsecString= QString::number(randsec);
QString randminString= QString::number(randmin);
editSec.setText(randsecString);
editMin.setText(randminString);
counter.set();//those are to input, they work fine, I checked
qDebug() << "Starting the Timer at " << (counter.count)/10;
auto start= std::chrono::system_clock::now();
counter.start(); //{timer->start();}
while(counter.count>0){
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
}
auto end= std::chrono::system_clock::now();
counter.stop();
auto check_ms= std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
int checkInt = check_ms.count();
int delta_s = randsec + randmin*60;
int delta = std::abs(checkInt - delta_s);
QVERIFY(delta < epsilon);
qDebug() << "Sec counted: " << counter.count/10;
qDebug() << "msec passed: " << checkInt;
}
}
QTEST_MAIN(tst_Counter)
#include "tst_counter.moc"
输出:
********* Start testing of tst_Counter *********
Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20180831)
PASS : tst_Counter::initTestCase()
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 3033
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 3000
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 3000
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
PASS : tst_Counter::initTestCD()
PASS : tst_Counter::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 33078ms
********* Finished testing of tst_Counter *********
在下面link你可以找到完整的例子。
我正在尝试为我命名为 Counter 的 class 创建一个单元测试。这样 class 应该每 0.1 秒减少它的值 "count" ,所以我在 class 构造函数中连接了该方法。在原来的程序中一切似乎都工作得很好,但是当我尝试 运行 单元测试器时,它似乎没有发生连接或者 QTimer 根本没有发送超时信号。
gitHub link: https://github.com/allocro/TimerLFdP/tree/master/testCounter
Counter::Counter(QLineEdit *editSec, QLineEdit *editMin, QObject *parent) :
QObject(parent)
{
timer= new QTimer(this);
[...]
connect(timer, &QTimer::timeout, this, &Counter::decCount);
}
编辑:K,我将按照要求将其他代码部分放入此处。
在前面的代码中,这里是我要测试的class的构造函数,decCount()所做的无非是:
void Counter::decCount(){
if (count>0)
count--;
else
timer->stop();
int countsec = count % 600;
int countmin = (count - countsec)/600;
QString secOut = QString::number(countsec/10) + "."
+QString::number(countsec%10);
emit showCountMin(countmin);
emit showCountSec(secOut);
}
以上信号与单元测试代码无关,它们在完整程序中使用。
现在,在tst_testCounter.cpp中,据我了解,是classic main的测试单元版本,我得到了
testCounter::testCounter() : QObject ()
{ int i;
editSec= new QLineEdit();
editMin= new QLineEdit();
counter= new Counter(editSec, editMin);
for(i=0; i<=10; i++){
int randsec= rand() %60;
int randmin= rand() %60;
randsec=3;
randmin=0; //To test the tester faster
QString randsecString= QString::number(randsec);
QString randminString= QString::number(randmin);
editSec->setText(randsecString);
editMin->setText(randminString);
counter->set();//those are to input, they work fine, I checked
std::cout << "Starting the Timer at " << (counter->count)/10 <<
"sec" <<std::endl;
counter->start(); //{timer->start();}
while(counter->count>0){
std::cout <<counter->count <<std::endl;
}
auto end= std::chrono::system_clock::now();
counter->stop();
auto check= std::chrono::duration_cast<std::chrono::seconds>(end -
start);
int checkInt= check.count();
if(checkInt==randsec+(randmin*60)){
std::cout << "Timer matches" <<std::endl;
}else{
std::cout << "Timer doesnt match" <<std::endl;
std::cout << "Sec counted: " << (counter->count)/10 <<std::endl;
std::cout << "Sec passed: " << checkInt <<std::endl;
break;
}
}
}
显然 .cpp 以
结尾QTEST_MAIN(testCounter)
#include "tst_testcounter.moc"
首先要记住的是QTimer
不是精确的,所以按秒的顺序检查会出问题,更好的测试验证以毫秒为单位的时间差小于一定的价值。
另一方面,指令:
while (counter-> count> 0) {
std::cout << counter-> count << std::endl;
}
您没有让事件循环工作,因此 QTimer 或信号可以工作。
你应该使用的是QCoreApplication::processEvents()
:
while(counter.count>0){
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
}
也建议测试的元素定义在方法内部,测试不在构造函数中给出,而是在槽中给出。
综合以上,并进行其他改进,得到:
counter.h
#ifndef COUNTER_H
#define COUNTER_H
#include <QObject>
class QTimer;
class QLineEdit;
class Counter : public QObject
{
Q_OBJECT
public:
explicit Counter(QLineEdit *setterSec, QLineEdit *setterMin, QObject *parent = nullptr);
QTimer *timer;
QLineEdit *setterSec;
QLineEdit *setterMin;
int count;
signals:
void showCountSec(const QString &count);
void showCountMin(int count);
public slots:
void decCount();
void start();
void stop();
void set();
};
#endif // COUNTER_H
counter.cpp
#include "counter.h"
#include <QTimer>
#include <QIntValidator>
#include <QLineEdit>
Counter::Counter(QLineEdit *editSec, QLineEdit *editMin, QObject *parent) :
QObject(parent),
timer(new QTimer(this)),
setterSec(editSec),
setterMin(editMin),
count(0)
{
setterSec->setValidator(new QIntValidator(0, 59, this));
setterMin->setValidator(new QIntValidator(0, 59, this));
connect(timer, &QTimer::timeout, this, &Counter::decCount);
}
void Counter::start(){
timer->start(100);
}
void Counter::stop(){
timer->stop();
}
void Counter::set(){
timer->stop();
count = setterSec->text().toInt()*10 + setterMin->text().toInt()*600;
int countsec = count % 600;
int countmin = (count - countsec)/600;
QString secOut = QString::number(countsec/10) + "." +QString::number(countsec%10);
emit showCountMin(countmin);
emit showCountSec(secOut);
}
void Counter::decCount(){
if (count > 0)
count--;
else
timer->stop();
int countsec = count % 600;
int countmin = (count - countsec)/600;
QString secOut = QString::number(countsec/10) + "." +QString::number(countsec%10);
emit showCountMin(countmin);
emit showCountSec(secOut);
}
tst_counter.h
#include <QtTest>
#include "counter.h"
#include <QLineEdit>
#include <iostream>
#include <cmath>
#include <QDebug>
// add necessary includes here
class tst_Counter : public QObject
{
Q_OBJECT
public:
tst_Counter();
~tst_Counter();
private slots:
void initTestCD();
};
tst_Counter::tst_Counter() : QObject ()
{
}
tst_Counter::~tst_Counter()
{
}
void tst_Counter::initTestCD(){
QLineEdit editSec;
QLineEdit editMin;
Counter counter(&editSec, &editMin);
const int epsilon = 50; // ms
for(int i=0; i<=10; i++){
int randsec= rand() %60;
int randmin= rand() %60;
randsec =3;
randmin =0; //To test the tester faster
QString randsecString= QString::number(randsec);
QString randminString= QString::number(randmin);
editSec.setText(randsecString);
editMin.setText(randminString);
counter.set();//those are to input, they work fine, I checked
qDebug() << "Starting the Timer at " << (counter.count)/10;
auto start= std::chrono::system_clock::now();
counter.start(); //{timer->start();}
while(counter.count>0){
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
}
auto end= std::chrono::system_clock::now();
counter.stop();
auto check_ms= std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
int checkInt = check_ms.count();
int delta_s = randsec + randmin*60;
int delta = std::abs(checkInt - delta_s);
QVERIFY(delta < epsilon);
qDebug() << "Sec counted: " << counter.count/10;
qDebug() << "msec passed: " << checkInt;
}
}
QTEST_MAIN(tst_Counter)
#include "tst_counter.moc"
输出:
********* Start testing of tst_Counter *********
Config: Using QtTest library 5.11.2, Qt 5.11.2 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 8.2.1 20180831)
PASS : tst_Counter::initTestCase()
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 3033
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 3000
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 3000
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
QDEBUG : tst_Counter::initTestCD() Starting the Timer at 3
QDEBUG : tst_Counter::initTestCD() Sec counted: 0
QDEBUG : tst_Counter::initTestCD() msec passed: 2999
PASS : tst_Counter::initTestCD()
PASS : tst_Counter::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 33078ms
********* Finished testing of tst_Counter *********
在下面link你可以找到完整的例子。