Configuring Tests in subfolders using Google Test and CMake - c++

This should be a fairly simple question, but given the black arts of project structuring using cmake, it will help quite a bit of people struggling with this.
I'm trying to get my codebase a little bit more organized. For this, I'm creating subfolders that contain the test suites according to their domain.
Google test itself is already compiling and running, the only thing is that with this restructure, Google Test can't find any of the Test Cases I have.
Here is my structure:
tests\
|
\domain1\
|CMakeLists.txt
|domain1_test.cpp
|domain1_test.hpp
|[.. more tests ...]
\domain2\
|CMakeLists.txt
|domain2_test.cpp
|domain2_test.hpp
|[.. more tests ...]
|main.cpp
|CMakeLists.txt
As you can see, I have two folders where tests live.
The CMakeLists.txt files in those are as follows:
SET(DOMAIN1_TEST_SRC
domain1_test.cpp
domain1_test.hpp)
ADD_LIBRARY(domain1testlib STATIC ${DOMAIN1_TEST_SRC})
TARGET_LINK_LIBRARIES(domain1testlib
${Boost_LIBRARIES}
domain_lib
gtest
)
TARGET_INCLUDE_DIRECTORIES(domain1testlib
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR})
The CMakeLists.txt in the main tests directory is:
add_subdirectory(domain1)
add_subdirectory(domain2)
ADD_EXECUTABLE(my_domain_tests main.cpp)
TARGET_LINK_LIBRARIES(my_domain_tests
${Boost_LIBRARIES}
domain1testlib
domain2testlib
comptestlib
gtest
)
add_test(MyTestSuite my_domain_tests)
What am I doing wrong?
Running tests just says that No tests were found.
Thanks!
UPDATE
Adding my main.cpp
It's really nothing special, just the boilerplate main.cpp file.
#include "gtest/gtest.h"
int main(int argc, char ** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

The problem is that no symbols from your domain*testlibs are referenced from your executable sources, i.e. main.cpp.
The TEST and TEST_F macros in Google Test automatically register the test cases with the test runner. So your test source files are the ones that actually include references to symbols in the gtest library and not the other way around. Thus, the linker will not include any of your actual test cases.
You should include the domain*_test.cpp and domain*_test.hppfiles as part of your executable sources instead of creating libraries with them. You can do that directly referencing the files or using a variable defined in each CMakeLists.txt with the list of sources.

What am I doing wrong?
Running tests just says that No tests were found.
to make available for "make test" and to work ctest inside build dir you need
ENABLE_TESTING()# Force "make test" to works
before add_test in CMakeLists.txt

Related

Corrections to CMakeList.txt file for Google testing?

I have been looking at examples of CMake to help me build my project with its test folder. The main issue is that I have to include all the test/.cpp* files in my test folder into tests/main.cpp for the tests to run. I think I should include my tests with the add_test call in my test/CMakeLists.txt. Below is my current CMakeLists file:
enable_testing()
find_package(GTest REQUIRED)
add_executable(test main.cpp)
target_include_directories(test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include)
target_link_libraries(test MainProjectLib ${GTEST_LIBRARIES})
And my main.cpp is the following.
#include "file_in_test1.cpp"
#include "file_in_test2.cpp"
#include <gtest/gtest.h>
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
I read some examples that use the standard CTest library for unit testing, but I am using Google Test. I would like to be able to run cmake, make, and then ./test to run all test methods found in file_in_test1.cpp and file_in_test2.cpp without having to directly import those files into test/main.cpp. What additions to CMakeLists.txt do I have to make?
The one line you could add at the end would be:
gtest_discover_tests(test)
This is a replacement for gtest_add_tests since cmake version 3.10, and then after you build everything, you can just run ctest and it will give you a nice summary of the tests it just ran. You can read more about this option here.
Also, just as a note, it would probably be better to make individual test files for each of the tests you have, rather than including the .cpp files in your main test file.
What I generally do is define an option to allow for testing and a function that creates the test I need (see below):
option(build_all_tests "Build all unit tests in the test directory." OFF)
if (build_all_tests)
include(CTest)
include(GoogleTest)
enable_testing()
## Function to create a new test based off the pre-defined naming template ##
function(new_test testname interiorDirectory)
add_executable(${testname} ${interiorDirectory}/${testname}.cpp)
target_link_libraries(${testname} ${GTEST_LIBRARIES})
gtest_discover_tests(${testname}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${interiorDirectory})
endfunction(new_test)
## Locate GTest ##
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
## Create all tests ##
new_test(test1 test/test1)
new_test(test2 test/test2)
...
endif()

CMake: How to reuse the same test_main.cpp for each test

I would like to use the test framework Catch2 in a monorepo in which there will be many components, each with their own tests. I'd like to use CMake to define all build targets.
Catch2 provides a simple means to generate a common main() function that will run all tests linked into the application. The source file (which I am calling test_main.cpp) is just these two lines:
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
I'd like to have just one copy of test_main.cpp in my source tree, and refer to it from each component directory that has tests (which will end up being on the order of hundreds of directories).
I can see how to set up CMake to work if I duplicated the test_main.cpp so that a redundant copy existed in each directory with tests, but I haven't figured out how to have just one copy. Is there a simple trick I've overlooked?
Try integrating Catch2 as a CMake interface library in the following way:
Add the single header file catch.hpp and test_main.cpp to a directory of their own (e.g., Catch2) along with the following CMakeLists.txt:
add_library(catch INTERFACE)
target_include_directories(catch INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
target_sources(catch INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/test_main.cpp")
The in your outermost CMakeLists.txt include Catch2 with add_subdirectory:
add_subdirectory(Catch2)
You can then set up test executables anywhere in the project in the following way:
add_executable(
project_tests EXCLUDE_FROM_ALL
test_case1.cpp
test_case2.cpp
...
)
target_link_libraries(project_tests catch)
Because test_main.cpp has been added to catch as an interface source file, it will be compiled as part of the test executable.

How to avoid mixing test and production code using GoogleTest?

I am starting to use GoogleTest. It seems that it needs a main file for running the tests:
Separate test cases across multiple files in google test
But currently in my demo application I already have a main file:
src/
-> MyType.h
-> main.cpp
-> Makefile
Which will eventually be my "production" application. I don't want to clutter that with gtest includes, macros etc.
Should I just create another main.cpp file in another folder e.g.: test/ that will contain all the specific gtest configuration so I would end up with:
src/
-> MyType.h
-> main.cpp
-> Makefile // Makefile for producing production code/binaries
Test/
-> MyTypeTest.h // Unittest for MyType
-> main.cpp // The "Test runner"
-> Makefile // Makefile for producing test executable
EDIT:
Found this based on cmake:
http://www.kaizou.org/2014/11/gtest-cmake/
which seems to be exactly what I am looking for.
The most sensible approach to this is to have a library for your production code and then two executables, one for production and another one for tests:
|-lib/
| |-Makefile
| |-mytype.h
| `-mytype.cpp
|-app/
| |-Makefile
| `-main.cpp
`-test/
|-Makefile
`-mytypetest.cpp
Notice that gtest distribution provides the gtest library and a gtest_main library with the standard main function for your test executable. So unless you need a custom main (rare case) you don't need to provide a main.cpp for your tests and can simply link against gtest_main, e.g. $(CC) mytypetest.cpp -o apptests -lapplib -lgtest_main -lgtest.
The library approach involves slightly more complex Makefiles, but it pays off in compilation time, since not having it implies you need to compile mytype.cpp once for production application and once for test executable.
There are probably a lot of ways to do this, but generally speaking, yes, you should add a test-specific main function to your project. This makes compilation a little bit more complex since you'll have to produce two separate binaries (one for your application and another for your tests) but this is a fairly typical setup.
I'd simply add a test.cpp file with a main and create a test target in my makefile so that I could either make - to build my production code - or make test - to build the tests. In actual projects I use cmake in very similar fashion (I sometimes bundle all common dependencies in a core.a library and then link both main and test against it).

GoogleTest several C++ projects in the same solution

I have e.g. 10 C++ projects in a solution SolA and want to UnitTest them with GoogleTest:
so I created a new solution SolATest and for every project of SolA an unit test project in SolATest!
Is it a good approach to load the SolA libraries implicit in SolATest/Projects and run every test project as an executable:
#include <iostream>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
int main(int argc, char **argv)
{
::testing::InitGoogleMock(&argc, argv);
int value = RUN_ALL_TESTS();
std::getchar(); // to hold the terminal open
return value;
}
or is there a more convenience way -> e.g. only have one executable in SolATest and load the other test projects as libraries (IMHO to have all cpp files in one test project is confusing)?!
Thx for any help
Either approach should work; it just depends on your preference. I tend to follow a project structure like the following:
Solution
|-- ProjectA
|-- ProjectATests
|-- ProjectB
|-- ProjectBTests
`-- TestLib
Where the projects (ProjectA, ProjectB) are libraries, and each test project (ProjectATests, ProjectBTests) is an executable. Note that we do not separate unit tests into a separate solution; they are always built and run alongside the production code. I like this structure for a few reasons:
It's easier to run just the tests that are related to your changes.
The development workflow is a bit more efficient, since when making changes to one library you only have to rebuild and link the corresponding test.
Whether you create a single test project or multiple, I would definitely recommend putting the project in the same solution as the code under test. Further, I would recommend setting up a post-build step for the test project(s) which runs the tests and fails the build if they don't pass.
Lastly, you might be wondering about that 'TestLib' project. I use that for the gtest/gmock fused sources, the definition of main(), and any other utilities that are shared between tests. That eliminates (or at least, reduces) code duplication between the various test projects.

Do you only need to build the googletest library once?

So firstly I'm new to testing frameworks and relatively new to C++ but am trying to wrap my head around GoogleTest. I'm working on a Windows machine, running "Git for Windows" (MSYS) and MinGW whilst using Sublime Text as my code editor. I am using make as my build tool, although the more I learn about cmake and its cross-platform focus makes me wonder if I should switch to let cmake create makefiles for me. (that's probably a whole other question)
What I'm struggling to understand is what precisly to do with the GoogleTest source package. I realise that I need to build the source into the library and then include that when compiling my tests, but how should I go about doing this? Google includes a cmake build script that generates env/compilier specific makefiles for building. Should I be using this? I feel like if i do so and it blindly works a lot of what is happening under the hood will go over my head. The readme file isn't eliviating my issues, as it implies that i should be building the library and my tests each time i wish the run them. Shouldn't a library be a standalone archive that needs compiling only once? I'm confused and I'm sure its my fault but i'd appreciate it if someone shed some light on this process for me.
You should keep in mind that make will not rebuild gtest if you don't change anything in gtest source code.
Below is my approach to the usage of cmake and gtest for unit testing.
You can add gtest source code by adding it as subdirectory in the root CMakeLists.txt file.
add_subdirectory(${CMAKE_SOURCE_DIR}/thirdparty/gtest ${CMAKE_CURRENT_BINARY_DIR}/gtest)
include_directories(${CMAKE_SOURCE_DIR}/thirdparty/gtest/include ${CMAKE_SOURCE_DIR}/thirdparty/gtest)
My application consist of individual modules containing test folder for unit testing. I have the following boilerplate loop to add each test to the global scope.
file(GLOB TEST_SRC_FILES *.cpp)
foreach(TEST_SRC_PATH ${TEST_SRC_FILES})
#get filename of your test without extension
get_filename_component(TEST_NAME ${TEST_SRC_PATH} NAME_WE)
add_executable(${TEST_NAME} ${TEST_NAME})
#here you link the test executable with gtest
target_link_libraries(${TEST_NAME} gtest gtest_main)
#-----------------------------
# you can link here your test to external libraries
#-----------------------------
add_test(${TEST_NAME} ${TEST_NAME})
#this is a list of all tests
set(PROJECT_TEST_NAMES ${PROJECT_TEST_NAMES} ${TEST_NAME})
endforeach()
#This assigns the list of tests to a property. This make the list available from the root scope.
get_property(UNIT_TESTS GLOBAL PROPERTY UNIT_TESTS)
set(UNIT_TESTS ${UNIT_TESTS} ${PROJECT_TEST_NAMES})
set_property(GLOBAL PROPERTY UNIT_TESTS ${UNIT_TESTS} )
Finally, in the root scope, I add a custom target named check which runs ctest on my unit tests.
#-----------------------------
# Running unit tests
#-----------------------------
get_property(UNIT_TESTS GLOBAL PROPERTY UNIT_TESTS)
if(DEFINED UNIT_TESTS)
add_custom_target(check COMMAND ctest -VV
DEPENDS ${UNIT_TESTS})
endif()
When I run make check, it runs unit tests from all modules, whereas make compiles without tests.