I'm working on a Qt project, and I need to be able to write unit tests for functions that depend on QNetworkAccessManager.
Google Mock seems like an overkill for my purposes, and I found this answer which suggest using a "linker trick" to mock the class. However, I'm very new to C++ (and C in general), and I'm having somewhat hard time in understanding the exact way I'm supposed to use this "trick". Am I supposed to manually change the header file to run the test, or is there some nicer way to do it (I'm assuming there is).
Any kind of an example on the header/code structure to do this correctly would be an immense help.
You could use linker tricks, but as QNetworkAccessManager can be subclassed, you might find it easier just to do that.
For example, if you want to make a version that doesn't actually connect, you could do something like:
class FailQNetworkAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
FailQNetworkAccessManager(QObject *parent = Q_NULLPTR):QNetworkAccessManager(parent){}
protected:
QNetworkReply* createRequest(Operation op, const QNetworkRequest &originalReq, QIODevice *outgoingData = Q_NULLPTR)
{
QNetworkReply* rep = QNetworkAccessManager::createRequest(op, originalReq, outgoingData);
// Queue the abort to occur from main loop
QMetaObject::invokeMethod(req, "abort", Qt::QueuedConnection);
return rep;
}
};
Then your test code can provide your class with the FailQNetworkAccessManager rather than the real one, and all requests should abort as soon as they're created. (This is just example code, I haven't actually tried this code yet - I would also recommend splitting this into header & cpp files).
You should also have a look at the Qt Test system, which is the built in test framework.
Related
Aside from recompiling rt.jar is there any way I can replace the currentTimeMillis() call with one of my own?
1# The right way to do it is use a Clock object and abstract time.
I know it but we'll be running code developed by an endless number of developers that have not implemented Clock or have made an implementation of their own.
2# Use a mock tool like JMockit to mock that class.
Even though that only works with Hotspot disabled -Xint and we have success using the code bellow it does not "persist" on external libraries. Meaning that you'd have to Mock it everywhere which, as the code is out of our control, is not feasible. All code under main() does return 0 milis (as from the example) but a new DateTime() will return the actual system millis.
#MockClass(realClass = System.class)
public class SystemMock extends MockUp<System> {
// returns 1970-01-01
#Mock public static long currentTimeMillis() { return 0; }
}
3# Re-declare System on start up by using -Xbootclasspath/p (edited)
While possible, and though you can create/alter methods, the one in question is declared as public static native long currentTimeMillis();. You cannot change it's declaration without digging into Sun's proprietary and native code which would make this an exercise of reverse engineering and hardly a stable approach.
All recent SUN JVM crash with the following error:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00000, pid=4668, tid=5736
4# Use a custom ClassLoader (new test as suggested on the comments)
While trivial to replace the system CL using -Djava.system.class.loader JVM actually loads up the custom classLoader resorting to the default classLoader and System is not even pushed trough the custom CL.
public class SimpleClassLoader extends ClassLoader {
public SimpleClassLoader(ClassLoader classLoader) {
super(classLoader);
}
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return super.loadClass(name);
}
}
We can see that java.lang.System is loaded from rt.jar using java -verbose:class
Line 15: [Loaded java.lang.System from C:\jdk1.7.0_25\jre\lib\rt.jar]
I'm running out of options.
Is there some approach I'm missing?
You could use an AspectJ compiler/weaver to compile/weave the problematic user code, replacing the calls to java.lang.System.currentTimeMillis() with your own code. The following aspect will just do that:
public aspect CurrentTimeInMillisMethodCallChanger {
long around():
call(public static native long java.lang.System.currentTimeMillis())
&& within(user.code.base.pckg.*) {
return 0; //provide your own implementation returning a long
}
}
I'm not 100% sure if I oversee something here, but you can create your own System class like this:
public static class System {
static PrintStream err = System.err;
static InputStream in = System.in;
static PrintStream out = System.out;
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) {
System.arraycopy(src, srcPos, dest, destPos, length);
}
// ... and so on with all methods (currently 26) except `currentTimeMillis()`
static long currentTimeMillis() {
return 4711L; // Your application specific clock value
}
}
than import your own System class in every java file. Reorganize imports in Eclipse should do the trick.
And than all java files should use your applicatikon specific System class.
As I said, not a nice solution because you will need to maintain your System class whenever Java changes the original one. Also you must make sure, that always your class is used.
As discussed in the comments, it is possible that option #3 in the original question has actually worked, successfully replacing the default System class.
If that is true, then application code which calls currentTimeMillis() will be calling the replacement, as expected.
Perhaps unexpectedly, core classes like java.util.Timer would also get the replacement!
If all of the above are true, then the root cause of the crash could be the successful replacement of the System class.
To test, you could instead replace System with a copy that is functionally identical to the original to see if the crashes disappear.
Unfortunately, if this answer turns out to be correct, it would seem that we have a new question. :) It might go like this:
"How do you provide an altered System.currentTimeMillis() to application classes, but leave the default implementation in place for core classes?"
i've tried using javassist to remove the native currentTimeMills, add a pure java one and load it using bootclasspath/p, but i got the same exception access violation as you did. i believe that's probably because of the native method registerNatives that's called in the static block but it's really too much to disassemble the native library.
so, instead of changing the System.currentTimeMills, how about changing the user code? if the user code already compiled (you don't have source code), we can use tools like findbugs to identify the use of currentTimeMillis and reject the code (maybe we can even replace the call to currentTimeMills with your own implementation).
Qt, which seems to name everything else with an initial Q, does this: #define signals signals in qobjectdefs.h.
However, GStream, not naturally, does not imagine signals to be a reserved word and does this
struct _GDBusInterfaceInfo
{
/*< public >*/
volatile gint ref_count;
gchar *name;
GDBusMethodInfo **methods;
GDBusSignalInfo **signals; <==================
GDBusPropertyInfo **properties;
GDBusAnnotationInfo **annotations;
};
in gdbusintrospection.h.
Am I just to assume that Qt and GStreamer don't play well together., or is there a way around this?
Note: Qt can be persuaded to #define signals signals if I don't #define Q_MOC_RUN. But that leads to problems with classes which are using
class
{
public:
// stuff
signals:
// stuff
private:
// stuff
};
As you might have guessed by now, I am trying to take over code from someone who is not around to support it and Google is not my friend:-(
[Update] Thanks, #IpApp fro the tip (which is not working, alas).
I have been given someone else's code. Apparently it build for target, but has never been built for unit test and I have to do that (why he mix & matched, I do not know).
When I use QT_NO_KEYWORDS in Eclipse CDT, I get errors because the class definition code does not use Q_SINGAL(S) - it uses the signals macro (which is now defined as signals) to define certain public members.
I am not allowed to alter the subsytsem code, just to mock its interfaces, but I am loathe to mock all of Qt & Glib, because of the effort.
Perhaps there is a way to use libraries for one or the other, rather than including their directories into the source path?
Just follow this documentation in your qmake project file:
CONFIG += no_keywords
If you are using something else than qmake, make sure that you define the following in your buildsystem:
QT_NO_KEYWORDS
Then, you need to make sure that you use Q_SIGNALS or Q_SIGNAL all over the place in your headers so that moc (meta object compiler) is still notified that it is a signal.
I have found another solution which as for me is more convenient and simple - you should include glib headers before Qt headers, and thats all. As glib code goes before, it is unaffected by Qt define statements.
I defined some signals which are emitted on different occasions:
signals:
void buttonXClicked(int x);
void numButtonsChanged(int num);
Now I would just like to see how these signals look like and if the parameters are correct. It seems there are several approaches to monitor the signals.
In the post here rohanpm refers to the parameter -vs which is specified closer here:
http://qt-project.org/doc/qt-4.8/qtestlib-manual.html#qtestlib-command-line-arguments
This seems to be an elegant and quick way of getting the information I require.
But to be honest I'm unable to understand how and where I have to run -vs. It's not part of qmake. Where else do I have to put it? (I'm pretty new to qt).
Related to the QSignalSpy it seems to be necessary to change the existing classes? Isn't there an "external" approach as well?
There is plenty of documentation around how to test a slot - but related to signals? Could I use a printf or cout somewhere?
I got this idea while reading more about the moc and its functionality. (At least while using NetBeans) I get additional to my File ButtonTest.cpp the file moc_ButtonTest.cpp. Inside is a method called:
// SIGNAL 0
void ButtonTest::buttonXClicked(int _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
I could hardly believe it was so easy but I've just added a
std::cout <<"buttonXClicked: "<<_t1;
and it seems to do exactly what I want.
As the linked documentation writes:
Runs the toUpper test function with all available test data, and the toInt test function with the testdata called zero (if the specified test data doesn't exist, the associated test will fail).
/myTestDirectory$ testMyWidget -vs -eventdelay 500
where testMyWidget is the test binary built. Here goes the -vs documentation:
-vs
outputs every signal that gets emitted
There is also some more documentation if you grep the help output:
/myTestDirectory$ testMyWidget --help | grep "\-vs"
-vs outputs every signal that gets emitted
If you happen to have trouble with writing QTestLib based unit tests, this is a good starting point for you with Qt 4:
QTestLib Manual
I'm trying to get my head around AOP and some Qt Code would really help.
From wikipedia here is some sample code (easy for a Qt/C++ programmer to read):
void transfer(Account fromAcc, Account toAcc, int amount, User user, Logger logger)
throws Exception {
logger.info("transferring money...");
if (! checkUserPermission(user)){
logger.info("User has no permission.");
throw new UnauthorizedUserException();
}
if (fromAcc.getBalance() < amount) {
logger.info("Insufficient Funds, sorry :( ");
throw new InsufficientFundsException();
}
fromAcc.withdraw(amount);
toAcc.deposit(amount);
//get database connection
//save transactions
logger.info("Successful transaction. :) ");
}
And then "aspectized":
void transfer(Account fromAcc, Account toAcc, int amount) throws Exception {
if (fromAcc.getBalance() < amount) {
throw new InsufficientFundsException();
}
fromAcc.withdraw(amount);
toAcc.deposit(amount);
}
aspect Logger
{
void Bank.transfer(Account fromAcc, Account toAcc, int amount, User user, Logger logger)
{
logger.info("transferring money...");
}
void Bank.getMoneyBack(User user, int transactionId, Logger logger)
{
logger.info("User requested money back");
}
// other crosscutting code...
}
Qt has signals and slots to decouple objects. But I still need to emit signals.
So: Can this be done with Qt or do I need some special framework/preprocessors as referenced in the wikipedia article?
I have a feeling that there must be some trick since Qt uses the Meta Object Compiler and some functionality might be "injected" with dynamic methods.... just spit-balling here ;)
Edit: To give a better context: I really like the dynamic aspects (power) of the Qt meta object with signals and slots and would like to keep a Qt feel to it. Thus, my idea is to make use of slots (or signals) as point cuts. For example:
If I define slot Bank::transfer(...) and then signal Bank::OnBeforeTranfer() and signal Bank::OnAfterTransfer(). If I then connect them to other aspects say Security::transfer() and Logger::transfer() (all QObjects) I can block calls (like fail OnBeforeTransfer).
But, if we then take it to the next evolution to get less and cleaner code I would like to get rid of the OnXXXX signals and connect the Bank::transfer slot to Security::transfer slot and Logger::transfer. Anything dynamic in Qt? : Like order of calling slots and and preventing next call in the "slot chain"?
This whole context can still be considered AOP right? I'm trying to stick to "method level point cuts" or am I totally beside the point here?
In what language are you planning to use Qt? I recently had to build a simple GUI in Qt around a python script and used the AOP python package Aspyct to do some quick before and after stuff. Qt is event-driven programming, I'd say get familiar with the Qt basics, many things are similar to AOP-style operations and then find some AOP libraries for the language you plan to use Qt in.
Another AOP framework you may consider using is AspectC++. I've played with it a bit and it seems to work quite well. They even have a whitepaper on the site that describes how AspectC++ can be used with Qt.
If you want to stay within the Qt framework, you could take a look at the State Machine Framework. (And get rid of the exceptions :)
Then you could just connect the Logger to state change events.
I'm trying to use QHttp for an update app. But there is a problem for me which I can't solve.
I try to download a file (works perfectly) but if there is no connection to the internet, the file is created but has 0 bytes. My old file is then overwritten with the empty file, which is not so good for the application trying to use the file. What I need is to check if the computer is connected to the internet.
Note: proxy may set. I used this example from Qt's homepage.
You should switch to the QNetworkAccessManager as Mike Suggested, here is an example of a slot on the finished() signal:
void ApplicationUpdate::replyFinishedhttpGetChangeLog(QNetworkReply* myReply) {
if (myReply->error() != QNetworkReply::NoError)
{
QByteArray returnedData = myReply->readAll();
if (returnedData.size() > 0) {
if( m_fileChangeLog->exists() )
{
m_fileChangeLog->close();
m_fileChangeLog->remove();
}
m_fileChangeLog->open(QIODevice::ReadWrite);
QDataStream out( m_fileChangeLog );
out.writeRawData(returnedData.data(), returnedData.size());
m_fileChangeLog->flush();
m_fileChangeLog->close();
}
}
}
Firstly, you should probably now be using QNetworkAccessManager rather than QHttp.
Using either of them, you should do a dummy query to a site you pretty much always know will be up (e.g. http://www.google.com/) and use that as a test to see if you have an internet connection.
A better way of doing this would be instead to use QNetworkAccessManager to read into a QByteArray and then check it isn't empty before writing to your file.
Whenever you write a file that might already exist, you should create a QTemporaryFile first, then, after successful download, rename it to the final name.
i ran into the same problem, after a bit of poking around, I've isolated the problem down to the project configuration file (.pro), in the broken configuration I was linking the networking library explicitly with the statement : "LIBS += -lQtNetwork". In the working configuration, I used the more formal (and qt compilant) approach of delcaring what Qt components are included in the project, like so: "QT = core gui network xml", adjust accordingly for your sitiation, the netowkring slots did not work on windows when explicitly linked but did work on linux. Using the qt compilant approach works on both platforms.