Skip to main content

Command Palette

Search for a command to run...

Running Python unit tests with CMake

Published
View as Markdown
Running Python unit tests with CMake

Welcome to the next pikoTutorial!

If you haven't read the previous pikoTutorial on setting up a Python project with CMake, you may want to check it out first because in today's article I'll be using the setup we've done there:

project/
├── app1/
    ├── CMakeLists.txt
    ├── main.py
    ├── requirements.txt
├── app2/
    ├── CMakeLists.txt
    ├── main.py
    ├── requirements.txt
├── app3/
    ├── CMakeLists.txt
    ├── main.cpp
├── build/
├── CMakeLists.txt

However, I will extend it with the test directories for each Python application:

project/
├── app1/
    ├── CMakeLists.txt
    ├── main.py
    ├── requirements.txt
    ├── test
        ├── test_app.py
├── app2/
    ├── CMakeLists.txt
    ├── main.py
    ├── requirements.txt
    ├── test
        ├── test_app.py
├── app3/
    ├── CMakeLists.txt
    ├── main.cpp
├── build/
├── CMakeLists.txt

Adding test targets

As I was showing in the pikoTutorial about running C++ tests with CMake, to enable running unit tests with ctest, we must extend app1/CMakeLists.txt file with add_test call:

# specify app1 virtual environment directory
set(APP1_VENV ${CMAKE_BINARY_DIR}/app1_venv)
# create virtual environment for app1
create_venv(${APP1_VENV} ${CMAKE_SOURCE_DIR}/app1/requirements.txt)
# add custom target to run app1
add_custom_target(run_app1
    COMMAND ${APP1_VENV}/bin/python ${CMAKE_SOURCE_DIR}/app1/main.py
    DEPENDS ${APP1_VENV}
)
# add unit tests
add_test(
    NAME app1_unit_test
    COMMAND ${APP1_VENV}/bin/python -m unittest discover ${CMAKE_SOURCE_DIR}/app1/test
)

The same goes for app2/CMakeLists.txt file. To make it work, we also need to add enable_testing() to the main CMakeLists.txt file.

Now I can run unit tests for both Python applications just by calling:

ctest

What will produce the following output:

    Start 1: app1_unit_test
1/2 Test #1: app1_unit_test ...................   Passed    0.07 sec
    Start 2: app2_unit_test
2/2 Test #2: app2_unit_test ...................   Passed    0.06 sec

Mixing unit tests between the languages

It's time extend the configuration - let's add tests not only for Python applications, but also for app3 which is a C++ application:

├── app3/
    ├── CMakeLists.txt
    ├── main.cpp
    ├── test
        ├── test_app.cpp

I will add the simplest C++ unit test definition to app3/CMakeLists.txt file:

# create an executable out of C++ code
add_executable(main main.cpp)
# add custom target to run app3
add_custom_target(run_app3
    COMMAND ${CMAKE_BINARY_DIR}/app3/main
    DEPENDS main
)
# add unit tests executable
add_executable(app3_unit_test test/test_app.cpp)
# add unit tests
add_test(
    NAME app3_unit_test
    COMMAND app3_unit_test
)

Now I call ctest and voilà - both Python and C++ tests executed with a single command:

    Start 1: app1_unit_test
1/3 Test #1: app1_unit_test ...................   Passed    0.06 sec
    Start 2: app2_unit_test
2/3 Test #2: app2_unit_test ...................   Passed    0.06 sec
    Start 3: app3_unit_test
3/3 Test #3: app3_unit_test ...................   Passed    0.00 sec