qtunit-testingqmlqttest

Unit testing for Qt Quick


I am very new to Qt and Qt Quick. I am validating the Qt Test unit testing framework for Qt Quick and I am not able to understand how to run the tests. Here's what I have, I have created a SUBDIRS project with the following structure:

ProjectSolution
   ProjectSolution.pro
   Project
      Project.pro
      Sources/main.cpp
      Resources/qml.qrc/main.qml
   ProjectTest
      ProjectTest.pro
      Sources/main.cpp
      Resources/qml.qrc/main.qml
      Resources/qml.qrc/tst_gui.qml

"Project" is the application to be tested and my test cases are in "ProjectTest/Resources/qml.qrc/tst_gui.qml".

tst_gui.qml:

import QtQuick 2.5
import QtTest 1.0

TestCase {
    name: "UI Testcase"
    when: windowShown

function test_button_click() {
    mouseClick(click_button, Qt.LeftButton, Qt.NoModifier)
}

function test_key_press() {
    keyClick(Qt.Key_Left)
    keyClick("a")
    }
}

I have a Button with id "click_button" in "Project/Resources/qml.qrc/main.qml" that I want to simulate. When I run the test project, I get failure with message:

FAIL!  : tst_gui::UI Testcase::test_button_click() Uncaught exception: click_button is not defined
C:\Users\sjayaprakash\Qt Test Projects\Qt Test Validation\QtTestValidation6\QtTestValidation6Test\tst_gui.qml(9) : failure location

I am sure I am doing something wrong. Could someone please help?


Solution

  • Finally, I was able to make it work. The test case was not able to find the button since it was in a different QML file. I tried importing and using property alias, both didn't work. I copied everything to my tst_gui.qml (leaving my main.qml empty) and it works fine now.

    tst_gui.qml (updated):

    import QtTest 1.0
    import QtQuick 2.5
    import QtQuick.Window 2.0
    import QtQuick.Controls 1.4
    import QtQuick.Controls.Styles 1.4
    import QtQuick.Dialogs 1.2
    import QtQml 2.2
    
    
    Rectangle {
        id: main_window
        visible: true
        width: Screen.width/2
        height: Screen.height/2
        color: "light grey"
    
        Rectangle {
    
            property alias click_button: click_button
    
            id: click_button
            width: main_window.width/4
            height: main_window.height/14
            color: "blue"
            x: main_window.width/2 - click_button.width/2
            y: main_window.height/2 - main_window.height/4
            Text {
                id: button_text
                text: qsTr("Click!")
                font.pointSize: 24
                color: "white"
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.verticalCenter: parent.verticalCenter
            }
    
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    //Log to console as a proof of button click simulation
                    console.log("Button was clicked!")
                }
            }
        }
    
        TextArea {
            id: textarea
            width: main_window.width/2
            height: main_window.height/8
            x: main_window.width/2 - textarea.width/2
            y: (main_window.height/2 - textarea.height/2) + main_window.height/8
    
            focus: true
            selectByKeyboard: true
            textColor: "darkblue"
            textFormat: TextEdit.PlainText
            wrapMode: TextEdit.WrapAtWordBoundaryOrAnywhere
    
            Keys.onLeftPressed: {
                //Log to console as a proof of key press simulation
                console.log("Left key was pressed!")
            }
        }
    
    
        TestCase {
            name: "UI Testcase"
            when: windowShown
    
            function test_button_click() {
                mouseClick(click_button, Qt.LeftButton, Qt.NoModifier)
            }
    
            function test_key_press() {
                keyClick(Qt.Key_Left)
            }
        }
    }
    

    In my main.cpp, I am just calling the macro:

    QUICK_TEST_MAIN("tst_gui")
    

    Probably, the right way to write unit tests is to separate them from actual code. For now, this works for me.