Recently I’ve played a bit with googletest in a couple of small projects: in murrayc-tuple-utils (and some later commits) and in prefixsuffix. It’s pretty straightforward and improved my test code and test result output (test-suite.log with autotools). Here are some notes.
Code Changes
I usually just use the standard autotools and CMake test features, sprinkling assert()s and “return EXIT_FAILURE;” in my C++ test code. However, googletest lets me replace a simple assert():
assert(foo.get_thing() == "hello");with an EXPECT_EQ() call that will give me a clue when the test fails:
EXPECT_EQ("hello", foo.get_thing());There are some other simple assertions.
googletest also wants me to declare test functions, previously simply declared like so,
void test_thing_something() {now like so:
TEST("TestThing", "Something") {which is all a bit macrotastic, unfortunately, but it works.
I chose to use the standard main() implementation, so I just removed my main() function that called these tests and compiled gtest_main.cc into the gtest library, as suggested in the googletest documentation.
Build Changes
googletest is meant to be built in your project, not built separately and just linked to as a library. For performance testing, I can see the benefit of building the test framework with exactly the same environment and options as the code being tested, but this does seem rather awkward. I guess it’s just what Google do in their monolithic builds so there’s nobody making an effort to support any other build system.
(Update: I wrote that in 2016, but now in 2019, I’ve noticed that added documentation about using pkg-config in August 2017Â (now here) and removed that advice about building it yourself, in July 2018. I’m very pleased about that. However, your Linux distro probably doesn’t have a package for the library. The Debian googletest package and the Ubuntu googletest package (the same as the libgtest-dev package), for instance, “does not contain a library to link against, but rather the source code to build the google test and mock libraries”.
Anyway, it’s fairly easy to add googletest as a git submodule and build the library in your autotools or CMake project. For autotools, I did this with libtool in murrayc-tuple-utils and without libtool in prefixsuffix.
Unfortunately, I had to list the individual googletest source files in EXTRA_DIST to make this work with autotool’s “make distcheck”.
This is easier with CMake, because googletest has a CMakeList.txt file so you can use “add_subdirectory (googletest)”. Of course, CMake doesn’t have an equivalent for “make distcheck”.
Also unfortunately, I had to stop using the wonderful -Wsuggest-override warning with warnings as error, because googletest doesn’t use the override keyword. I think it hasn’t really caught up with C++11 yet, which seems odd as I guess Google is using at least C++11 in all its code.
Conclusion
The end result is not overwhelming so far, and it’s arguable if it’s worth having to deal with the git submodule awkwardness. But in theory, when the tests fail, I now won’t have to add so many printfs to find out what happened. This makes it a bit more like using JUnit with Java projects.
Also in theory, the test output would integrate nicely with a proper continuous integration system, such as Jenkins, or whatever Google use internally. But I’m not using any of those on these projects. Travis-CI is free with github projects, but it seems to be all about builds, with no support for test results.
You do not have to give up -Wsuggest-override (or any other warning that makes gtest barf when building it or using its headers).
Just build gtest-all.cc and gtest_main.cc with -w (I used to pass -Wno-suggest-override and a couple of other warnings but -w is just simpler) and add the directory where its headers are with -isystem.
Thanks. -isystem has indeed solved that problem. I’ve committed changes to use it in both problems. It’s awkward to complicate the build to do that, but I like being able to use as many warnings as possible again.
I do not know much about Automake but in my own Meson based projects I do this:
gtest_dir = ‘googletest/googletest’
gtest_incdir = include_directories(join_paths(gtest_dir, ‘include’), is_system : true)
libgtest = static_library(‘gtest’,
cpp_args : [‘-w’],
include_directories : [include_directories(gtest_dir), gtest_incdir],
sources : [
join_paths(gtest_dir, ‘src’, ‘gtest-all.cc’),
join_paths(gtest_dir, ‘src’, ‘gtest_main.cc’)
])
gtest_dep = declare_dependency(dependencies : dependency(‘threads’),
include_directories : gtest_incdir,
link_with : libgtest)
in a meson.build in a external/third_party subdir in the root after having added googletest as a git submodule in that dir (e.g. external/googletest is the submodule and the above meson snippet goes in external/meson.build).
And then depend on gtest_dep in my unit test executables. Maybe it is not much simpler but it isolates it in a good way I think. The outside world (other meson.build files) only have to know about gtest_dep.
(There is a built in gtest dependency in Meson but it uses libgtest.so etc shipped by distros if available which is someting the googletest authors does not recommend. See https://github.com/google/googletest/blob/master/googletest/docs/FAQ.md#why-is-it-not-recommended-to-install-a-pre-compiled-copy-of-google-test-for-example-into-usrlocal . It also does not work to use prebuilt distro .so files if one wants to build with different stdlib implementations (libstdc++ vs libc++). So the above snippet is the best I can come up with at the moment.)
Ouch, that meson.build snippet was not formatted in a nice way by WordPress. Its all there at least. :)
Since you have already swallowed the bitter pill of “macrotastic” (nice word!) testing frameworks, then you could consider using Catch (https://github.com/philsquared/Catch) or Doctest (https://github.com/onqtam/doctest) for testing. They have an option of being just a single header to spare you some build system woes. And in the end, they are probably not so different from googletest.
Thanks.
If you want to use googletest with cmake, you might find ExternalProject module useful [1]. I’ve recently started using it in one of my projects as well [2].
[1] https://cmake.org/cmake/help/v3.0/module/ExternalProject.html
[2] https://github.com/loganek/workertracker/blob/master/tests/CMakeLists.txt