How to write Qt test for a Qt project - c++

I have read the 5 tutorial from QT-test website. But they are not what I want.
I want to build a project and its unit test part is detached from the main program.
For example:
In main program has a push-botton on widgets and if it was clicked then a Qlabel will show a number.
If I run the test programm, It would mock MouseClicked Event on that button, then verify if the value which shows up on Qlabel is our expectations.
My question is how can I get my test program linked to the main program so that I can access its members? Besides that I want to build the project using CMake, how should I write the CMakeLists for the test project?
---root
|---test
|----CmakeLists.txt
|----test.cpp
|----test.h
|---build
|----main.cpp // only int main function
|----QMainwindows.cpp
|----QMainwindows.h
|----QMainwindows.ui
|----CmakeLists.txt
And the CMakeLists.txt in root
cmake_minimum_required(VERSION 3.5)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
project(myproject VERSION 0.1 LANGUAGES CXX)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
set(PROJECT_SOURCES
main.cpp
QMainwindows.cpp
QMainwindows.h
QMainwindows.ui
)
add_executable(myproject ${PROJECT_SOURCES})
target_link_libraries(myprojectPRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
I am also confused how to access the members from mainwindow in our test. I mean I cant include the ui_mainwindow.h and create an UI_Mainwindow Instance

I found an approach that could answer my question.
In test part I can use findchild<T>("WidgetsName") to get access to ui members of any class.
reference : How do you get a widget's children in Qt?
This may not be a universal solution and if anyone has a better idea, I would be grateful.

Related

Support included directory in CLion

I have project in CLion constructed from 2 major parts(2 projects). One is dynamic library(/engine) and the second one is executable(/gui)
My project structure is:
CMakes looks like this:
CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
add_subdirectory(engine)
add_subdirectory(gui)
/engine/CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 17)
add_library(enginelib SHARED library.cpp library.h)
/gui/CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 17)
include_directories(../engine)
add_executable(gui main.cpp)
target_link_libraries(gui PRIVATE enginelib)
Project builds correctly, gui is using engine and it works.
However Clion underscores including from engine and doesn't show things from engine.
How to fix this?
Thanks for help :)
Btw, It's my first time setting project like this, am I including the engine into gui correctly? Or there is a better way to do this?

CLion and Qt5: tuning qmake

I have a set-up as explained elsewhere, e.g. here. I have Qt5 installed system-wide,
and have the requisite lines in my CMakeLists.txt. My IDE is Clion.
Everything in a simple GUI goes fine until I add Q_OBJECT macro (I want this to connect signals to slots). Now, when I do this, I get the undefined reference to vtable-type error,
that is also found in abundance on the net.
My confusion arises from the fact that some recommend using Qt5-bundled cmake for your project,
which essentially means "just for GUI" I need to change the toolchain. But some actually say nothing about it. What all say is that
Qt runs qmake every time Q_OBJECT is added/deleted
Now, how to capture that in my CMakeLists.txt? -- the relevant part thereof is given below.
I've seenmoc and qmake inside /usr/lib/qt5/bin; so how to communicate this to CLion?
# ----- GUI part -----
# Qt5 inclusion
# The meta object compiler is one of the core functionality of Qt, it reads a C++ header file and if it finds a
# Q_OBJECT macro, it will produces a C++ source file containing meta object code for the class.
# It's the mechanism that allow signal and slots to work.
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# set(CMAKE_PREFIX_PATH $ENV{QT_DIR}/$ENV{QT_VERSION}/gcc_64/lib/cmake)
set(CMAKE_PREFIX_PATH /usr/lib/qt5/bin/)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
# Enable user interface compiler (UIC)
# The user interface compiler is a program that read XML from the .ui file
# generated by Qt Interface Designer and generate C++ code from it.
set(CMAKE_AUTOUIC ON)
if(CMAKE_VERSION VERSION_LESS "3.7.0")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
endif()
set(CMAKE_MODULE_PATH /usr/lib/qt5)
# #see: https://stackoverflow.com/questions/51994603/cmake-qt5-undefined-reference-to-qprinterqprinterqprinterprintermode
SET(QT5_MODULES Widgets PrintSupport)
find_package(Qt5 COMPONENTS ${QT5_MODULES} REQUIRED)
add_subdirectory(${PROJECT_SOURCE_DIR}/extern/qcustomplot)
add_executable(gui
${PROJECT_SOURCE_DIR}/gui/main.cpp
${PROJECT_SOURCE_DIR}/extern/qcustomplot/qcustomplot.cpp)
set_target_properties(gui PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(gui
PUBLIC
Qt5::Core Qt5::Widgets qcustomplot)
Never mind the verbose comments; my initial GUI training being in Java Swing, I found them useful.
EDIT: what helped me was the qt5_wrapper_cpp thing mentioned in
Qt 5 cmake fails with undefined reference to vtable on hello world with inc & src as subdirs
Q_OBJECT macro requires code generation. That's why you got undefined reference exceptions. I don't remember exactly how to configure a cmake project for Qt, but I would recommend reading https://cmake.org/cmake/help/latest/manual/cmake-qt.7.html.
Something like set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC TRUE) should help you.

Cmake and Qt5: Using different components of Qt5 in different subdirectories

I want to use the Qt5 library in my subdirectories without adding the all components to each subdirectory. In the parent CMakeLists I use find_package(Qt5) to make sure that the library exists and the Qt5_DIR variable is set. Example:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
find_package(Qt5 COMPONENTS Core REQUIRED)
add_subdirectory(exec1)
add_subdirectory(exec2)
In the subdirectory exec1 I want to use the Qt5::Xml component. As far as I have understood CMake, the Qt5_DIR variable is passed to the subdirectories. Therefore I do not have to use find_package again. Is this assumption correct? Example:
exec1/CMakeLists.txt
project(exec1)
set(SRC exec1.cpp)
set(HDR exec1.h)
add_executable(exec1 ${SRC} ${HDR})
target_link_libraries(exec1 Qt5::Core Qt5::Xml)
In a second subdirectory exec2 I want to add other components of Qt5. Example:
exec2/CMakeLists.txt
project(exec2)
set(SRC exec2.cpp)
set(HDR exec2.h)
add_executable(exec2 ${SRC} ${HDR})
target_link_libraries(exec2 Qt5::Core Qt5::Websockets)
Does it make any difference if I add all components in the parent CMakeLists.txt instead of choosing for each subproject only some components?
How do I handle this case so that I can exchange Qt5 components in the subdirectories without affecting other subdirectories?
Or is it more convenient to add the find_package to each subdirectory instead of using it once in the parent CMakeLists.txt?
Any suggestions and tipps are appreciated.
If you want to use Qt5 components in subdirectories while using find_package only once in the root CMakeLists.txt -- which is IMHO the right thing to do -- you will have to list all the wanted components when finding Qt.
So following your example, root CMakeLists.txt should be something like that:
cmake_minimum_required(VERSION 3.0)
find_package(QT5 COMPONENTS Xml Websocket REQUIRED)
add_subdirectory(exec1) # will use Xml
add_subdirectory(exec2) # will use Websocket
Note that I removed Core since it is implicitly added as a dependency of both Xml and Websocket. Same goes for the subdirectories:
add_executable(exec1 ${SRC} ${HDR})
target_link_libraries(exec1 QT5::Xml)
Here exec1 implicitly links against Core component because it is a dependency of Xml.

Copy all qt resources using cmake

I would like to compile qml application using cmake.
Here is my cmake file:
cmake_minimum_required(VERSION 3.3)
project(QMLTest)
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES main.cpp)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Quick REQUIRED)
add_executable(QMLTest main.cpp)
include_directories(${Qt5Widgets_INCLUDES})
add_definitions(${Qt5Widgets_DEFINITIONS})
qt5_use_modules(QMLTest Widgets Quick )
And main.cpp:
#include <QGuiApplication>
#include <QQuickView>
int main(int argc, char** argv)
{
QGuiApplication app(argc, argv);
QQuickView view;
view.resize(800, 480);
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.setSource(QUrl::fromLocalFile("gui/MainWidnow.qml"));
view.show();
return app.exec();
}
When I try to compile it I get an error:
gui/MainWidnow.qml: File not found.
How can I copy all my qt resources into application directory?
Instead of copying your QML files into the application directory, I would instead recommend using Qt's resource system (1), which allows you to embed resources such as QML files directly in your executable. To do this, you need to first create a resource file such as resources.qrc to register your application resources:
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
<file>gui/MainWindow.qml</file>
</qresource>
</RCC>
You then add the resource file to your CMake configuration. This will create a source file from the resource file which you need to include in your application sources:
qt5_add_resources(RCC_SOURCES resources.qrc)
add_executable(QMLTest ${RCC_SOURCES} main.cpp)
Once this is done, you can use a file URL in the format :/gui/MainWindow.qml to refer to this resource, which is now embedded in your application binary. Qt will automatically resolve it for you:
view.setSource(QUrl(":/gui/MainWindow.qml"));
There are some more details in the Qt documentation on deploying QML applications (2).
I would like to extend the accepted answer.
I would write this as a comment but I don't have the reputation.
It is possible to use Qt independent CMAKE function calls instead of qt5_add_resources():
set(CMAKE_AUTORCC ON)
add_executable(myexe main.cpp resource_file.qrc)
And then you can refer to the files using :/file_relative_to_qrc
There are multiple ways to do that, for example:
add_custom_target(copy-runtime ALL
COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/gui/MainWindow.qml
${CMAKE_BINARY_DIR}
DEPENDS QMLTest)
I didn't test that, but you'll get the idea. Another option would be e.g. to use CMake's install command to install the runtime files locally with "make install". However, in this case the best option would be to use Qt's resource system like ajshort recommends in his answer and embed the needed files in the executable.

VTK CMakeLists.txt for test classes

A typical 'CMakeLists.txt' included with a VTK wiki example is shown below;
cmake_minimum_required(VERSION 2.8)
PROJECT(Arrow)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
add_executable(Arrow MACOSX_BUNDLE Arrow)
if(VTK_LIBRARIES)
target_link_libraries(Arrow ${VTK_LIBRARIES})
else()
target_link_libraries(Arrow vtkHybrid)
endif()
I'm able to build the examples successfully in Windows 7 and Visual Studio 2012.
I would like to write a 'CMakeLists.txt' file so that I can build/run a test class (i.e. This one ReebGraph/Testing). I'm assuming I'm right in saying that they require different kinds of make files. The 'CMakeLists.txt' for 'TestReebGraph.cxx' is shown below.
vtk_add_test_cxx(TestReebGraph.cxx NO_DATA NO_VALID NO_OUTPUT)
vtk_test_cxx_executable(${vtk-module}CxxTests)
How would I write one for the testing class? Do I somehow have to merge the two?
The cmake commands vtk_* are for writing tests inside of the VTK CMake system. What you'll want is to first enable_testing() in your CMakeLists.txt. Then you'll have to change the function TestReebGraph to be called 'main' in TestReebGraph.cxx. You can then use add_test(TestReebGraph TestReebGraph.cxx) to build the test that you have presumably copied into your project directory.