Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Qt Creator will not find QML Unit Tests
QtWS25 Last Chance

Qt Creator will not find QML Unit Tests

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
5 Posts 3 Posters 812 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    JOwens_RTT
    wrote on last edited by
    #1

    The Problem
    I'm trying to develop a testing suite for my project. Right now, I can get pure C++ tests to compile and run within Creator's automated testing tools. Now I'm trying to figure out how to test the QML side of the project. I've gotten to where I can compile a pure QML test, navigate to it in the build directory, and run it using the command line. However, Creator will not run it using the automated tool because it cannot detect the test. How can I get Creator to find and run the QML/Quick unit tests?

    Project Details
    CMake V3.25.1
    Qt V6.2.4
    Qt Creator V11.0.0 (didn't work on V10 either)

    The test I'm trying to develop is the Position unit test.

    MyProject // Design Studio / Creator project
      |->cmakeTools // CMake helper functions
      |->content/.../Lines  // UI files
      |    |-> Position.qml // File I'm trying to test
      |->inc // Global Headers
      |->lib // Main libraries
      |    |->API // An example library
      |         |->CMakeLists.txt
      |         |->api.cpp
      |         |->api.h
      |->src // Global sources
      |->sim // Simulation files
      |->test // Unit Tests
           |->API // An example C++ Unit Test
           |    |->CMakeLists.txt
           |    |->ut_api.cpp
           |    |->ut_api.h
           |->content/.../Lines // UI Unit Tests
                |->Position // The test that won't work
                     |->CMakeLists.txt
                     |->ut_mycontrol.cpp
                     |->tst_mycontrol.qml
    
    // * Every folder shown contains a CMakeLists.txt file, but I haven't shown it for simplicity.
    

    I can configure and build the project as it currently stands, including the Position unit test. However, unlike the API and other C++ unit tests, I cannot run it form Qt Creator using the automated testing tools. Here is a screenshot of the Creator test list.

    Screenshot from 2023-07-27 12-52-32.png

    Position Test Output (Command Line)

    ./Position_Test
    Warning: Ignoring WAYLAND_DISPLAY on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.
    ********* Start testing of position *********
    Config: Using QtTest library 6.2.4, Qt 6.2.4 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 10.3.1 20210422 (Red Hat 10.3.1-1)), ubuntu 22.04
    PASS   : position::Position::initTestCase()
    FAIL!  : position::Position::test_fail() 2 + 2 = 5
       Actual   (): 4
       Expected (): 5
       Loc: [/home/jowens/Projects/build-MyProject-amd64-Debug/test/content/Program/Lines/Position/Position_Test_qml/tst_position.qml(15)]
    PASS   : position::Position::test_pass()
    PASS   : position::Position::cleanupTestCase()
    PASS   : position::Position::initTestCase()
    FAIL!  : position::Position::test_fail() 2 + 2 = 5
       Actual   (): 4
       Expected (): 5
       Loc: [/home/jowens/Projects/build-MyProject-amd64-Debug/test/content/Program/Lines/Position/tst_Position.qml(15)]
    PASS   : position::Position::test_pass()
    PASS   : position::Position::cleanupTestCase()
    PASS   : position::Position::initTestCase()
    FAIL!  : position::Position::test_fail() 2 + 2 = 5
       Actual   (): 4
       Expected (): 5
       Loc: [/home/jowens/Projects/build-MyProject-amd64-Debug/test/content/Program/Lines/Position/tst_position.qml(15)]
    PASS   : position::Position::test_pass()
    PASS   : position::Position::cleanupTestCase()
    Totals: 9 passed, 3 failed, 0 skipped, 0 blacklisted, 15ms
    ********* Finished testing of position *********
    

    If what I've found out so far is correct, Qt Tests are detected by finding the QTest::qExec() command in the source file. Quick Tests do not seem to have this statement and so are not detected under that heading, but I haven't found any information on how they are supposed to be detected.

    File Contents
    - ut_position.cpp

    #include <QtQuickTest>
    #include <QtTest/qtest.h>
    
    QUICK_TEST_MAIN(position)
    
    #include "ut_position.moc"
    
    

    - tst_position.qml

    import QtQuick 6.2
    import QtTest 1.0
    
    import lib.Program
    import lib.Pose
    
    TestCase {
        name: "Position"
    
        function test_pass() {
            compare(2 + 2, 4, "2 + 2 = 4")
        }
    
        function test_fail() {
            compare(2 + 2, 5, "2 + 2 = 5")
        }
    }
    

    - Position/CMakeLists.txt

    cmake_minimum_required(VERSION 3.21.1)
    
    project(Position_Test)
    
    message(STATUS "Quick Test Root Directory: ${QUICK_TEST_SOURCE_DIR}")
    
    set(MSG_HEADER "Processing ${CMAKE_CURRENT_SOURCE_DIR}")
    message(STATUS "${MSG_HEADER}: --- START ---")
    
    message(STATUS "${MSG_HEADER}: Include List [${INCLUDE_DIRECTORIES}]")
    
    # Get tools
    include(${CMAKE_SOURCE_DIR}/cmakeTools)
    
    # Set sources, headers, and dependencies
    set(sources
        ut_position.cpp
    )
    # set(headers
    #     ut_Position.h 
    # )
    set(depend 
        Program 
        Pose 
        Stringable 
        GCodeElement 
        content
        Poseplugin
        Programplugin
        contentplugin
        MyProjectplugin
        Qt${QT_VERSION_MAJOR}::QuickTest
    )
    
    # Create test (located in cmakeTools)
    generate_test(${PROJECT_NAME}  
        SOURCE ${sources} 
        DEPEND ${depend}
    )
    
    qt_add_qml_module(${PROJECT_NAME}
        URI ${PROJECT_NAME}_qml
        VERSION 1.0
        QML_FILES
            tst_position.qml
    )
    # HEADER ${headers} 
    
    # Copy qml files to build directory
    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tst_position.qml ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
    
    # These are located in cmakeTools (details not provided)
    include_directory()
    ListDependencies()
    
    message(STATUS "${MSG_HEADER}: ---- END ----")
    

    - MyProject/cmakeTools (used in Position/CMakeLists.txt)

    # generate_test
    # arg1: test name
    # arg2: sources
    # arg3: headers
    # arg4: dependencies
    function(generate_test)
        # Parse arguements
        set(nameProvided FALSE)
        set(sourcesProvided FALSE)
        set(headersProvided FALSE)
        set(dependenciesProvided FALSE)
        set(parseMode "NAME")
    
        set(testName)
        set(sources)
        set(headers)
        set(dependencies)
    
        foreach(arg IN LISTS ARGV)
            # Determine mode if applicable
            if(${arg} STREQUAL "SOURCE")
                set(parseMode "SOURCE")
            elseif(${arg} STREQUAL "HEADER")
                set(parseMode "HEADER")
            elseif(${arg} STREQUAL "DEPEND")
                set(parseMode "DEPEND")
            else ()
                # No mode change, parse arguement
                if(${parseMode} STREQUAL "NAME")
                    set(nameProvided TRUE)
                    set(testName ${arg})
                elseif(${parseMode} STREQUAL "SOURCE")
                    set(sourcesProvided TRUE)
                    list(APPEND sources ${arg})
                elseif(${parseMode} STREQUAL "HEADER")
                    set(headersProvided TRUE)
                    list(APPEND headers ${arg})
                elseif(${parseMode} STREQUAL "DEPEND")
                    set(dependenciesProvided FALSE)
                    list(APPEND dependencies ${arg})
                endif()
            endif()
        endforeach()
    
        # Make sure minimum required arguments have been provided
        if(NOT ${nameProvided})
            message(FATAL_ERROR " ${MSG_HEADER}: No test name provided! Please provide a test name as the first argument.")
        endif()
        if(NOT ${sourcesProvided})
            message(WARNING " ${MSG_HEADER}: No sources provided.")
        else()
            message(STATUS "${MSG_HEADER}: Sources: ${sources}")
        endif()
        if(NOT ${headersProvided})
            message(WARNING " ${MSG_HEADER}: No headers provided.")
        else()
            message(STATUS "${MSG_HEADER}: Headers: ${headers}")
        endif()
        if(NOT ${dependenciesProvided})
            message(STATUS "${MSG_HEADER}: No dependencies provided.")
        else()
            message(STATUS "${MSG_HEADER}: Dependencies: ${dependencies}")
        endif()
    
        # Create Test
        message(STATUS "${MSG_HEADER}: Creating unit test project ${testName}...")
        project(pro_${testName} LANGUAGES CXX)
        find_package(Qt6 REQUIRED COMPONENTS Core Gui Test Widgets Quick QuickTest)
    
        message(STATUS "${MSG_HEADER}: Creating executable...")
        qt_add_executable(${testName} ${headers} ${sources})
        message(STATUS "${MSG_HEADER}: done.")
    
        message(STATUS "${MSG_HEADER}: Adding dependencies...")
        target_link_libraries(${testName} PRIVATE
            Qt${QT_VERSION_MAJOR}::Core
            Qt${QT_VERSION_MAJOR}::Gui
            Qt${QT_VERSION_MAJOR}::Test
            Qt${QT_VERSION_MAJOR}::Quick
            Qt${QT_VERSION_MAJOR}::Widgets
            ${dependencies}
        )
        message(STATUS "${MSG_HEADER}: done.")
    
        message(STATUS "${MSG_HEADER}: Creating install path...")
        install(TARGETS ${testName}
            RUNTIME DESTINATION "CRWeld_UI/test/${testName}"
            BUNDLE DESTINATION "CRWeld_UI/test/${testName}"
            LIBRARY DESTINATION "CRWeld_UI/test/${testName}"
        )
        message(STATUS "${MSG_HEADER}: done.")
    
        message(STATUS "${MSG_HEADER}: ${testName} created.")
    endfunction()
    
    Q 1 Reply Last reply
    2
    • J JOwens_RTT

      The Problem
      I'm trying to develop a testing suite for my project. Right now, I can get pure C++ tests to compile and run within Creator's automated testing tools. Now I'm trying to figure out how to test the QML side of the project. I've gotten to where I can compile a pure QML test, navigate to it in the build directory, and run it using the command line. However, Creator will not run it using the automated tool because it cannot detect the test. How can I get Creator to find and run the QML/Quick unit tests?

      Project Details
      CMake V3.25.1
      Qt V6.2.4
      Qt Creator V11.0.0 (didn't work on V10 either)

      The test I'm trying to develop is the Position unit test.

      MyProject // Design Studio / Creator project
        |->cmakeTools // CMake helper functions
        |->content/.../Lines  // UI files
        |    |-> Position.qml // File I'm trying to test
        |->inc // Global Headers
        |->lib // Main libraries
        |    |->API // An example library
        |         |->CMakeLists.txt
        |         |->api.cpp
        |         |->api.h
        |->src // Global sources
        |->sim // Simulation files
        |->test // Unit Tests
             |->API // An example C++ Unit Test
             |    |->CMakeLists.txt
             |    |->ut_api.cpp
             |    |->ut_api.h
             |->content/.../Lines // UI Unit Tests
                  |->Position // The test that won't work
                       |->CMakeLists.txt
                       |->ut_mycontrol.cpp
                       |->tst_mycontrol.qml
      
      // * Every folder shown contains a CMakeLists.txt file, but I haven't shown it for simplicity.
      

      I can configure and build the project as it currently stands, including the Position unit test. However, unlike the API and other C++ unit tests, I cannot run it form Qt Creator using the automated testing tools. Here is a screenshot of the Creator test list.

      Screenshot from 2023-07-27 12-52-32.png

      Position Test Output (Command Line)

      ./Position_Test
      Warning: Ignoring WAYLAND_DISPLAY on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.
      ********* Start testing of position *********
      Config: Using QtTest library 6.2.4, Qt 6.2.4 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 10.3.1 20210422 (Red Hat 10.3.1-1)), ubuntu 22.04
      PASS   : position::Position::initTestCase()
      FAIL!  : position::Position::test_fail() 2 + 2 = 5
         Actual   (): 4
         Expected (): 5
         Loc: [/home/jowens/Projects/build-MyProject-amd64-Debug/test/content/Program/Lines/Position/Position_Test_qml/tst_position.qml(15)]
      PASS   : position::Position::test_pass()
      PASS   : position::Position::cleanupTestCase()
      PASS   : position::Position::initTestCase()
      FAIL!  : position::Position::test_fail() 2 + 2 = 5
         Actual   (): 4
         Expected (): 5
         Loc: [/home/jowens/Projects/build-MyProject-amd64-Debug/test/content/Program/Lines/Position/tst_Position.qml(15)]
      PASS   : position::Position::test_pass()
      PASS   : position::Position::cleanupTestCase()
      PASS   : position::Position::initTestCase()
      FAIL!  : position::Position::test_fail() 2 + 2 = 5
         Actual   (): 4
         Expected (): 5
         Loc: [/home/jowens/Projects/build-MyProject-amd64-Debug/test/content/Program/Lines/Position/tst_position.qml(15)]
      PASS   : position::Position::test_pass()
      PASS   : position::Position::cleanupTestCase()
      Totals: 9 passed, 3 failed, 0 skipped, 0 blacklisted, 15ms
      ********* Finished testing of position *********
      

      If what I've found out so far is correct, Qt Tests are detected by finding the QTest::qExec() command in the source file. Quick Tests do not seem to have this statement and so are not detected under that heading, but I haven't found any information on how they are supposed to be detected.

      File Contents
      - ut_position.cpp

      #include <QtQuickTest>
      #include <QtTest/qtest.h>
      
      QUICK_TEST_MAIN(position)
      
      #include "ut_position.moc"
      
      

      - tst_position.qml

      import QtQuick 6.2
      import QtTest 1.0
      
      import lib.Program
      import lib.Pose
      
      TestCase {
          name: "Position"
      
          function test_pass() {
              compare(2 + 2, 4, "2 + 2 = 4")
          }
      
          function test_fail() {
              compare(2 + 2, 5, "2 + 2 = 5")
          }
      }
      

      - Position/CMakeLists.txt

      cmake_minimum_required(VERSION 3.21.1)
      
      project(Position_Test)
      
      message(STATUS "Quick Test Root Directory: ${QUICK_TEST_SOURCE_DIR}")
      
      set(MSG_HEADER "Processing ${CMAKE_CURRENT_SOURCE_DIR}")
      message(STATUS "${MSG_HEADER}: --- START ---")
      
      message(STATUS "${MSG_HEADER}: Include List [${INCLUDE_DIRECTORIES}]")
      
      # Get tools
      include(${CMAKE_SOURCE_DIR}/cmakeTools)
      
      # Set sources, headers, and dependencies
      set(sources
          ut_position.cpp
      )
      # set(headers
      #     ut_Position.h 
      # )
      set(depend 
          Program 
          Pose 
          Stringable 
          GCodeElement 
          content
          Poseplugin
          Programplugin
          contentplugin
          MyProjectplugin
          Qt${QT_VERSION_MAJOR}::QuickTest
      )
      
      # Create test (located in cmakeTools)
      generate_test(${PROJECT_NAME}  
          SOURCE ${sources} 
          DEPEND ${depend}
      )
      
      qt_add_qml_module(${PROJECT_NAME}
          URI ${PROJECT_NAME}_qml
          VERSION 1.0
          QML_FILES
              tst_position.qml
      )
      # HEADER ${headers} 
      
      # Copy qml files to build directory
      configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tst_position.qml ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
      
      # These are located in cmakeTools (details not provided)
      include_directory()
      ListDependencies()
      
      message(STATUS "${MSG_HEADER}: ---- END ----")
      

      - MyProject/cmakeTools (used in Position/CMakeLists.txt)

      # generate_test
      # arg1: test name
      # arg2: sources
      # arg3: headers
      # arg4: dependencies
      function(generate_test)
          # Parse arguements
          set(nameProvided FALSE)
          set(sourcesProvided FALSE)
          set(headersProvided FALSE)
          set(dependenciesProvided FALSE)
          set(parseMode "NAME")
      
          set(testName)
          set(sources)
          set(headers)
          set(dependencies)
      
          foreach(arg IN LISTS ARGV)
              # Determine mode if applicable
              if(${arg} STREQUAL "SOURCE")
                  set(parseMode "SOURCE")
              elseif(${arg} STREQUAL "HEADER")
                  set(parseMode "HEADER")
              elseif(${arg} STREQUAL "DEPEND")
                  set(parseMode "DEPEND")
              else ()
                  # No mode change, parse arguement
                  if(${parseMode} STREQUAL "NAME")
                      set(nameProvided TRUE)
                      set(testName ${arg})
                  elseif(${parseMode} STREQUAL "SOURCE")
                      set(sourcesProvided TRUE)
                      list(APPEND sources ${arg})
                  elseif(${parseMode} STREQUAL "HEADER")
                      set(headersProvided TRUE)
                      list(APPEND headers ${arg})
                  elseif(${parseMode} STREQUAL "DEPEND")
                      set(dependenciesProvided FALSE)
                      list(APPEND dependencies ${arg})
                  endif()
              endif()
          endforeach()
      
          # Make sure minimum required arguments have been provided
          if(NOT ${nameProvided})
              message(FATAL_ERROR " ${MSG_HEADER}: No test name provided! Please provide a test name as the first argument.")
          endif()
          if(NOT ${sourcesProvided})
              message(WARNING " ${MSG_HEADER}: No sources provided.")
          else()
              message(STATUS "${MSG_HEADER}: Sources: ${sources}")
          endif()
          if(NOT ${headersProvided})
              message(WARNING " ${MSG_HEADER}: No headers provided.")
          else()
              message(STATUS "${MSG_HEADER}: Headers: ${headers}")
          endif()
          if(NOT ${dependenciesProvided})
              message(STATUS "${MSG_HEADER}: No dependencies provided.")
          else()
              message(STATUS "${MSG_HEADER}: Dependencies: ${dependencies}")
          endif()
      
          # Create Test
          message(STATUS "${MSG_HEADER}: Creating unit test project ${testName}...")
          project(pro_${testName} LANGUAGES CXX)
          find_package(Qt6 REQUIRED COMPONENTS Core Gui Test Widgets Quick QuickTest)
      
          message(STATUS "${MSG_HEADER}: Creating executable...")
          qt_add_executable(${testName} ${headers} ${sources})
          message(STATUS "${MSG_HEADER}: done.")
      
          message(STATUS "${MSG_HEADER}: Adding dependencies...")
          target_link_libraries(${testName} PRIVATE
              Qt${QT_VERSION_MAJOR}::Core
              Qt${QT_VERSION_MAJOR}::Gui
              Qt${QT_VERSION_MAJOR}::Test
              Qt${QT_VERSION_MAJOR}::Quick
              Qt${QT_VERSION_MAJOR}::Widgets
              ${dependencies}
          )
          message(STATUS "${MSG_HEADER}: done.")
      
          message(STATUS "${MSG_HEADER}: Creating install path...")
          install(TARGETS ${testName}
              RUNTIME DESTINATION "CRWeld_UI/test/${testName}"
              BUNDLE DESTINATION "CRWeld_UI/test/${testName}"
              LIBRARY DESTINATION "CRWeld_UI/test/${testName}"
          )
          message(STATUS "${MSG_HEADER}: done.")
      
          message(STATUS "${MSG_HEADER}: ${testName} created.")
      endfunction()
      
      Q Offline
      Q Offline
      qiqi99
      wrote on last edited by
      #2

      @JOwens_RTT Did you find a solution?

      A 1 Reply Last reply
      0
      • A Offline
        A Offline
        Anumas
        wrote on last edited by
        #3

        I'm facing the same issue.

        Say hello to a bright day.-

        Anumas.

        1 Reply Last reply
        0
        • A Offline
          A Offline
          Anumas
          wrote on last edited by Anumas
          #4

          I could fix it. The solution is pretty simple. Make sure to have in your CMakeLists.txt in root dir enable_testing().

          // CMakeLists.txt in /
          cmake_minimum_required(VERSION 3.20)
          
          project(QuickTestLab VERSION 0.1 LANGUAGES CXX)
          enable_testing()
          
          set(CMAKE_CXX_STANDARD 23)
          set(CMAKE_CXX_STANDARD_REQUIRED ON)
          set(CMAKE_AUTORCC ON)
          
          
          find_package(Qt6 6.5 REQUIRED COMPONENTS Quick QuickTest)
          
          qt_standard_project_setup(REQUIRES 6.5)
          
          qt_add_executable(appQuickTestLab
              main.cpp
          )
          
          qt_add_qml_module(appQuickTestLab
              URI QuickTestLab
              VERSION 1.0
              QML_FILES
                  Main.qml
          )
          ...
          

          Then in tests/CMakeLists.txt make sure you've set QUICK_TEST_SOURCE_DIR.

          // tests/CMakeLists.txt
          project(Tests LANGUAGES CXX)
          enable_testing()
          
          add_executable(labelmessage
              tst_labelmessage.cpp tst_labelmessage.qml
          )
          
          add_test(NAME labelmessage COMMAND labelmessage)
          
          target_link_libraries(
              labelmessage
              PRIVATE Qt6::QuickTest
              PRIVATE Qt6::Qml
              # PRIVATE appQuickTestLab
              # PRIVATE appQuickTestLabplugin
          )
          
          
          // no need to copy around qml test files for shadow builds - just set the respective define
          add_definitions(-DQUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
          ...
          

          And that's it!

          Say hello to a bright day.-

          Anumas.

          1 Reply Last reply
          0
          • Q qiqi99

            @JOwens_RTT Did you find a solution?

            A Offline
            A Offline
            Anumas
            wrote on last edited by
            #5

            @qiqi99 Check out my solution.

            Say hello to a bright day.-

            Anumas.

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved