PDA

View Full Version : Message as QReturnArgument?



QphiuchuS
7th June 2013, 12:33
Hi!

I'm supposed to test an application with QTest. Now I would like to test a login function, which is void, but returns (I suppose) QMessages (I'm not sure though). Ok, I call the function from my test class:


TheClassToTest * test = new TheClassToTest();

QMetaObject::invokeMethod(test, "login", Qt::DirectConnection, Q_ARG(QString, username) , Q_ARG(QString, password));


This works, but obviously I am not comparing anything yet. If the login attempt is successful, the ClassToTest shows a Message (and this message in fact appears when i call my test class):


statusBar()->showMessage("You're logged in now!", 4000);

Since this function is void, this is the only reaction.

Now I would like to somehow get the content of this message an compare it to a predefined string, to see, if the login was indeed successful. In a very naive attempt I tried it this way:



TheClassToTest * test = new TheClassToTest();
QMessageBox returnVal;
QString result = "You're logged in now!"

QMetaObject::invokeMethod(test, "login", Qt::DirectConnection, Q_RETURN_ARG(QMessageBox, returnVal), Q_ARG(QString, username) , Q_ARG(QString, password));

QCOMPARE(returnVal.text(), result);


The MessageBox no longer appears if I now run the test, but the test still fails since the string I try to retrieve from my returnVal is empty:



Actual (returnVal.text()):
Expected (result): You're logged in now!


I could not find how QStatusBar::showMessage() is implemented, maybe the error is that showMessage does not use a QMessageBox?

I would really appreciate some help.

Thank you.

anda_skoa
7th June 2013, 16:23
I don't see a reason why you want to use invokeMethod() here.
Simply call the login slot directly.

As for the message, use a QSignalSpy to connect to the QStatusBar's messageChanged() signal and then compare the value from the spy.

Something like



QSignalSpy messageSpy(statusBar, SIGNAL(messageChanged(QString)));

// perform login

QCOMPARE(messageSpy.count(), 1); // expect one emit
QCOMPARE(messageSpy[0].count(), 1); // signal has one argument
QCOMPARE(messageSpy[0][0].toString(), expectedMessage);


Cheers,
_

QphiuchuS
7th June 2013, 17:39
I don't see a reason why you want to use invokeMethod() here.
Simply call the login slot directly.

As for the message, use a QSignalSpy to connect to the QStatusBar's messageChanged() signal and then compare the value from the spy.

Something like



QSignalSpy messageSpy(statusBar, SIGNAL(messageChanged(QString)));

// perform login

QCOMPARE(messageSpy.count(), 1); // expect one emit
QCOMPARE(messageSpy[0].count(), 1); // signal has one argument
QCOMPARE(messageSpy[0][0].toString(), expectedMessage);


Cheers,
_

Thank you for your answer, I will look into the QSignalSpy. I tried to call the method directly but can't, since it is a private slot. Me googeling how to test a private method resulted in using invokeMethod().

anda_skoa
8th June 2013, 10:40
I tried to call the method directly but can't, since it is a private slot. Me googeling how to test a private method resulted in using invokeMethod().

Ah, yes, I see.
Ideally this wouldn't be necessary, i.e. if a unit's interface it difficult to test, then the interface is most likely not they way it should be.
But if there is no way around such a restriction at the given time, then things like that can indeed be helpful :)

Another thing: since login procedure are often asynchronous, a test will have to wait while keeping the event loop running. That can be done with either QTest::qWait() or a local event loop that exits on receiving the target signal.

Cheers,
_