Testing Qt Quick for Android applications with Squish
July 04, 2025 by Olli Vuolteenaho | Comments
In previous blog posts (here, here and here), we’ve talked about embedding QML components into native Android apps – a concept we call Qt Quick for Android. It provides an easy way to spice up your Android application with Qt or even write the whole UI in QML without leaving the warm, cuddly comfort of Android Studio and the Android build system. In this blog post we'll take a look at how you can leverage Qt Quality Assurance tools to test the apps you create with this technology.
Our tool of choice for testing GUIs is Squish, the fantastic cross-platform solution. But “Wait, I’ve used Squish, and you must choose a different edition of Squish for Android and Qt. How could this work with only one edition?” you might helpfully ask. Well, Squish supports testing Qt and Android content together as highlighted in this older blog post and we can use the same concepts here with just some build differences.
To summarize the linked blog post from the previous paragraph, Squish supports testing Qt applications with native Android elements using separate ApplicationContexts. You need to add Squish hooks to the Qt component and create a test package from the final APK that adds instrumentation to the Android parts. After this, you can connect to the application with Squish for Android and easily switch between the contexts to test both “sides” (the Qt Quick and native Android components) of your Qt Quick for Android application. How wonderful! Let’s take a look at the details of how to create a testable application and execute test cases. You can use some examples shipped with Qt as a starting point.
Instrumenting the application
To communicate with the app, Squish needs to make it testable by instrumenting it. In this case, because the Application Under Test (AUT) has two components with different architectures (Qt and native Android), we must instrument both. The Qt Quick component requires a bit more work because we build it as an Android Archive (AAR) file instead of an APK.
Hooking into the Qt Quick component
For the Qt part one, can follow the official documentation for installing Squish for Qt for Android testing. We're going to use Squish's Qt built-in hook. To start, let's add the hook to our build by amending the following to CMakeLists.txt in our Qt Quick project:
Set(SquishQtbuiltinHook_DIR /Users/ollivuolteenaho/squish-9.0.1-qt69x-android-arm64-v8a)
# Look for Squish, optional and allowed to fail
find_package(SquishQtBuiltinHook)
# Add Squish to application target if found
if(SquishQtBuiltinHook_FOUND)
squish_qt_add_builtin_hook(qtquickview ATTACH_PORT 4567)
endif()
The port can be chosen freely outside system ports. We then need to register the Qt Quick app as an AUT in Squish either from the IDE (Squish for Android) or from command line. Using the command line is easy with Squish's tooling:
$ squishserver --config addAttachableAUT qtquickview localhost:4567
And because we're connecting to the device or emulator with ADB we need to forward the local port to the target device.
$ adb forward tcp:4567 tcp:4567
If we were building a regular Qt for Android app we would be done now. But because the Qt component is built into an AAR instead of an APK using the Qt Gradle Plugin, some of the Squish hook automation isn’t working (at least at the moment). Therefore, we need to manually include some libraries in the final APK.
I’m testing on an arm64-v8a device, so I’ll create a directory under the Android project and copy the Squish libraries there:
mkdir –p app/libs/arm64-v8a
cp ~/squish-9.0.1-qt69x-android-arm64-v8a/libs/*.so app/libs/arm64-v8a
cp ~/squish-9.0.1-qt69x-android-arm64-v8a/libs/extensions/qt/*.so app/libs/arm64-v8a
And then to bundle these files into the APK we need to modify the “android” section in app/build.gradle.kts:
android {
sourceSets.getByName("main").jniLibs.srcDir("libs")
...
Or if you’re old school and still using Groovy DSL:
android {
SourceSets.main.jniLibs.srcDir 'libs'
...
All of this can (and probably should) be automated, of course. Now after building the example app the Qt Quick side of the app is connectable and testable. Hooray.
Instrumenting the native Android component
For the Android part, Squish provides its nifty apk-tool tool that instruments the application and installs it to the target device/emulator with one command. Something like:
$ /Applications/Squish_for_Android_9.0.0/bin/apk-tool -j $JAVA_HOME -pkg
my_first_testable_app.apk -d emulator-5554 -o instrumented_app.apk
will take your magnificent Qt Quick for Android application, instrument it and install it to the "emulator-5554" device for you.
Executing tests
We then start and connect to the hooks in the app in both contexts. I'll use Python here because it's pretty ubiquitous and simple to read, but you can script Squish test cases in several languages.
For ease of use we'll store the application contexts in Squish's test module during the init() function. Squish for Android's startApplication() starts the application with the name of the package (com.example.qtquickview_java in this case) and hooks to it. After that attachToApplication() can be used to connect to the "qtquickview" registered AUT.
import test
application_name = "qtquickview"
package_name = “com.example.qtquickview_java”
def init():
test.log(“Start application in Android context”)
test.ctx_android = squish.startApplication(package_name)
test.log(“Connect to application in Qt context”)
test.ctx_qt = squish.attachToApplication(application_name)
Now, in the actual test case, we can switch between the contexts quickly to test the components interacting with each other or whatever we want. Woohoo! In the example below, the app (one of our examples) using Qt Quick for Android has a Qt Quick component and a native Android component that cause changes to happen in the other component. More specifically, to understand the code snippet, the native Android "Change Color" button will change the background color of the Qt Quick component. To test that we can write something like:
def main():
test.log("Read Qt Quick component background color")
qt_background_color = squish.waitForObjectExists(names.qt_MainRectangle).color
test.log("Switch to Android context")
squish.setApplicationContext(test.ctx_android)
android_button = squish.waitForObjectExists(names.android_ChangeColor_Button)
test.log("Tap on native Android Change Color button")
squish.tapObject(android_button)
test.log("Switch to Qt Quick context")
squish.setApplicationContext(test.ctx_qt)
test.log("Verify the Qt Quick component background color has changed")
new_background_color = squish.waitForObjectExists(names.qt_MainRectangle).color
test.verify(new_background_color != qt_background_color)
And as we execute the test code with Squish, we can see everything working perfectly.
And it’s as simple as that.
Final
What are you waiting for? Go buy Qt and Squish. Preferably several times. 😉
Blog Topics:
Comments
Subscribe to our newsletter
Subscribe Newsletter
Try Qt 6.9 Now!
Download the latest release here: www.qt.io/download.
Qt 6.9 is now available, with new features and improvements for application developers and device creators.
We're Hiring
Check out all our open positions here and follow us on Instagram to see what it's like to be #QtPeople.