10

I would like to create two executables: one executable for the application, and one for the testing of the application. To that end, I have the following in my CMakeLists.txt file:

include_directories(include)

file(GLOB SOURCE "src/*.cc")
file(GLOB TEST "test/*.cc")

add_executable(interest_calc ${SOURCE})
add_executable(interest_calc_test "src/interest_calc.cc" ${TEST})

Since both src and test directories contain main functions, I have to manually add source files to the "test" executable. Is there another, non-manual, way to add required source files to the "test" executable?

Further, is there a better way to test functionality than creating a separate test executable? If so, what/how?

Ari
  • 4,121
  • 8
  • 40
  • 56
  • `Is there another, non-manual, way to add required source files to the "test" executable?` - E.g. you may place file `main.cc` into different folder, and add it manually to the list. `Further, is there a better way to test functionality than creating a separate test executable? If so, what/how?` - This question is **broad** as "What is a better way to write software". There are numerous testing strategies. Just choose one of them which seems to fit your purpose. – Tsyvarev Jan 23 '17 at 17:19
  • Note that globbing up all source files into your executable works if all you have is the one executable with a handful of source files... but as your project grows, manually adding source files to units, libraries, executables and tests as appropriate _is_ usually considered the better approach. You will face temporary executables, proof-of-concept sources, outdated sources only kept around for reference, and a plethora of other reasons to not just "compile everything into one". – DevSolar Aug 31 '18 at 07:39
  • I hope you will find the answer to your question [here](https://stackoverflow.com/questions/41883841/confusion-about-unit-tests-googletest-and-projects-folder-files/73220054#73220054) – Vitalii Aug 03 '22 at 10:31

4 Answers4

8

One way to improve your process would be to pull the guts of your executable into a library, then have a nominal "main" executable which just calls into your library and a "test" executable which exercises the library however you want to test it.

This way, any changes you need to make go into the library and the executable build process is untouched.

Edit to show CMake with your example:

include_directories(include)

file(GLOB SOURCE "src/*.cc")

# Remove main from library, only needed for exec.
list(REMOVE_ITEM SOURCE "main.cc")

file(GLOB TEST "test/*.cc")

add_library(interest_calc_lib STATIC ${SOURCE})
add_executable(interest_calc "main.cc")
target_link_libraries(interest_calc interest_calc_lib)
add_executable(interest_calc_test ${TEST})
target_link_libraries(interest_calc_test interest_calc_lib)
mascoj
  • 1,313
  • 14
  • 27
7

There are already some good answers from Soeren and mascoj but I would like to give a more concrete recommendation.

When you already have a CMakeLists.txt for your executable and you like to add testing, I recommend adding a static dummy library. This library can have all the sources of the executable except the main method (it may be easiest to single out the main method in a separate file if you do not have that already). Using a static library will give you two benefits:

  • The final executable will behave exactly as your current one, so there is no need to deal with distribution of a new, shared library
  • You do not need to deal with exporting symbols or throwing exceptions across shared object boundaries

The changes to your CMakeLists.txt can be quite small. I will give an example here, assuming you use cmake 3.0 or newer. First, an example of CMakeLists.txt before adding the dummy library:

project(MyProject)
set(SOURCES src/First.cc src/Second.cc src/Third.cc)

add_executable(${PROJECT_NAME} ${SOURCES} src/Main.cc)
target_include_directories(${PROJECT_NAME}
    ${CMAKE_CURRENT_SOURCE_DIR}/include
    ${CMAKE_CURRENT_SOURCE_DIR}/src
    ${CMAKE_CURRENT_BINARY_DIR})
target_compile_options(${PROJECT_NAME}
    $<$<CXX_COMPILER_ID:GNU>:-Wall;-pedantic)
target_compile_definitions(${PROJECT_NAME}
    $<$<CONFIG:Debug>:DEBUG;_DEBUG>)
set_target_properties(${PROJECT_NAME}
    PROPERTIES CXX_STANDARD 14)
target_link_libraries(${PROJECT_NAME}
    Threads::Threads)

To add the dummy library and testing, you need to introduce a new target with a different name. I choose here to use ${PROJECT_NAME}_lib because this will be very non-intrusive on the CMakeLists.txt. Here is the updated version. Notice the use of ${PROJECT_NAME}_lib in place of ${PROJECT_NAME} in almost all places. Most properties are now passed down to the executable by making them PUBLIC. Only calls to set_target_properties() are not transitive and must be duplicated for library and executable.

project(MyProject)
set(SOURCES src/First.cc src/Second.cc src/Third.cc)

add_library(${PROJECT_NAME}_lib STATIC ${SOURCES})
add_executable(${PROJECT_NAME} src/Main.cc)
target_include_directories(${PROJECT_NAME}_lib PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/include
    ${CMAKE_CURRENT_SOURCE_DIR}/src
    ${CMAKE_CURRENT_BINARY_DIR})
target_compile_options(${PROJECT_NAME}_lib PUBLIC
    $<$<CXX_COMPILER_ID:GNU>:-Wall;-pedantic)
target_compile_definitions(${PROJECT_NAME}_lib PUBLIC
    $<$<CONFIG:Debug>:DEBUG;_DEBUG>)
set_target_properties(${PROJECT_NAME}_lib
    PROPERTIES CXX_STANDARD 14)
set_target_properties(${PROJECT_NAME}
    PROPERTIES CXX_STANDARD 14)
target_link_libraries(${PROJECT_NAME}
    ${PROJECT_NAME}_lib
    Threads::Threads)

Now you can link your tests against ${PROJECT_NAME}_lib with a different main method.

emmenlau
  • 958
  • 12
  • 20
1

You could do like this :
In the current CMakeLists.txt, put these lines :

add_subdirectory(src)
add_subdirectory(test)

and then, in each directories add a CMakeLists.txt that link correctly sources to each files.

About test, I've heard that CMake can do test automation, but I don't really know how it works.

1

In my opinion the best solution is to create a library (shared or static) and two executables (one for the main program and one for the test main). After that you should link the library against the two applications. In this answer I write down a explanation with a little example how you could managed the project with cmake.

Community
  • 1
  • 1
Soeren
  • 1,725
  • 1
  • 16
  • 30