- Installing googletest
- Making sure cmake finds and compiles googletest
- Adding local unit tests
- The CMakeLists.txt file in UnitTests
- The actual test C++ code
- The output from make
In this article we take a short detour into the problem of continuous unit testing of code that contains MPI calls and use either mpich or Open MPI. I have recently moved from CTest-based testing to a combination of CMake and googletest. The reason for the shift is the convenience
googletest provides. However, the
googletest primer and advanced manual do not contain many examples and can be cryptic at times. I hope this article will provide pointers to those who run into a roadblock when testing MPI applications with
I typically install
googletest as a submodule in my git repository. For example,
There are several caveats when using git submodules. For our purposes, we only have to remember that when we clone the repository we have to use
Other tips can be found in a nicely condensed form in Sentheon’s blog.
Making sure cmake finds and compiles googletest
To make sure that
googletest can be found and is built during the compile process, I add the following to by root
The first line is needed because I have not been successful in passing the
clang compiler name to
googletest without specifying the full path. I’m sure one can use a more general approach, but I haven’t felt the need to spend the time trying to figure out a better way. The
add_subdirectory command is all that is needed for
cmake to compile
googletest and produce static libraries.
Adding local unit tests
Next I add a
UnitTests directory in my directory of interest and modify the local
CMakeLists.txt to be able to find the
UnitTests directory. For example,
In this case I am going to test my Smoothed Particle Hydrodynamics code.
The CMakeLists.txt file in UnitTests
Now we are finally really to add our unit tests to the build chain. The
CMakeLists.txt file in the
UnitTests directory has two sections (which can be simplified if you are so inclined).
In the first section, we find the location of the
googletest headers and libraries:
Note that the two
googletest libraries that we use are
In the second section, we add the actual test that requires
MPI. Once again, these details can be abstracted into a
cmake function if you so desire.
add_executable line identifies the unit test program
testSPHParticleScatter.cpp which tests the scatter operation between two MPI processes.
target_link_libraries lists the libraries that are needed: the
googletest libraries (
GTEST_LIB) and our coupled DEM-SPH code library (
Then we set up a command to run (
MPI_COMMAND) and make it use
mpirun. You can generalize this if you want.
Finally we, add the
add_custom_command line that tells
cmake to run the
MPI_COMMAND after the build is complete (
The actual test C++ code
Now that the build system has been configured, we just write our unit test
First, we include the required headers:
Note that we are using the Boost MPI wrappers.
The MPI test environment class
But we cannot use the
boost::mpi::environment call to set up
MPI (because the
environment object is deleted before
googletests are run). Instead, we have to set up a custom environment to run our
MPI tests by creating a
MPIEnvironment class that extends the
::testing::Environment class provided by
SetUp function calls
MPI_Init and sets up the environment while the
TearDown function calls ‘MPI_Finalize`. All tests are performed when the environment is active.
main test function
main function in typically not needed in standard
googletest tests and is generate by some internal magic. However, we do need a
main function in
testSPHParticleScatter.cpp because we are using
mpirun to run the test.
The MPI specific environment is created by the
AddGlobalTestEnvironment function to which we pass a
MPIEnvironment object. The object is deleted internally by
The tests in
testSPHParticleScatter.cpp are then run using
RUN_ALL_TESTS(). Note that this function returns from
main and, therefore, and non-googletest environment objects created in main (e.g., with boost::mpi::environment) are deleted before the tests are run.
The actual test
Finally, we add an actual test to
testSPHParticleScatter.cpp as follows:
The test can be written in the standard way and numerous examples can be found on the web. Of course, we have to be careful about keeping in mind that the test will be run on two processes in this particular case.
Boost MPI environment created by
boost::mpi::environment allows MPI calls to fail without throwing an exception. For example, in my
Patch code discussed in an earlier article, I have
I deliberately send invalid
neighborCoords to this function to find out if a patch is a boundary patch. This does not create a problem when I use the
boost::mpi::environment set up. But when setting up the environment explicitly for the unit tests, I have to add
before I call
MPI_Cart_rank to make sure I don’t get errors when I use invalid values of
The output from make
Now, if we run
make (after setting up the makefiles with cmake, of course), we not only compile the code but also run the unit test! In this particular case, here’s what the output looks like:
I hope this article has been of use to you. Our series on communication between patches will continue when I get some free time.
If you have questions/comments/corrections, please contact banerjee at parresianz dot com dot zen (without the dot zen).
📅 11.08.2017 📁 MPI · C++