Search code examples
c++cmakegnu-makegoogletest

Minimalistically building a test for a simple header using CMake


I have a C++ header which contains a class with a method like below. Lets say its a header only library I have.

// MyHeader.hpp
#pragma once

#include <string>

namespace myheaderonlylibrary {

class MyClass {
public:
    unsigned int Func1(const std::string& str) {
        if (!str.empty())
            return 10;
        else
            return 0;
    }
};

}

To test the above method I heve the following gtest source file inside a folder called unittest which is like the convention followed.

// MyTests.cpp
#include <limits.h>
#include "gtest/gtest.h"

#include "../MyHeader.hpp"

TEST(MyTest, Test_Something) {
    myheaderonlylibrary::MyClass my_object;
    unsigned int expected_value = 0;
    EXPECT_EQ(expected_value, my_object.Func1(""));
}

All I want to do is build the test using Cmake and run the test. So, following is my CMakeLists.txt.

// CMakeLists.txt
cmake_minimum_required(VERSION 3.4)
set(MyheaderOnlyLibrary_HEADERS
    MyHeader.hpp
)

set(MyheaderOnlyLibrary_unittest
    unittest/MyTests.cpp
)

find_package(GTest REQUIRED)
enable_testing ()
add_executable(MyheaderOnlyLibraryTests ${MyheaderOnlyLibrary_unittest})

After the above is set, I do a cmake .. and make which results with the following error.

"_main", referenced from:
     implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64

Question:
I am not a pro in CMake. My question is that if all I want to do is to be able run tests, then should I be doing an add_executable? Is this correct approach when the only thing I want is to build and run the tests? Seems like the error when calling make is because add_executable is looking for main method like in a normal executable and its not finding it.

What is the correct way to build a test only project where a header file is the only thing to be tested?

How to run the tests after building? Looks like there is a command CTest to run the tests built using CMake?

Environment:
I am building this on a macOS with clang as the compiler with C++11.


Solution

  • Just like a normal C++ program you need to have a main function to execute, for a googletest unit test you can use the following:

    int main(int argc, char** argv)
    {
        testing::InitGoogleTest(&argc, argv);
        return RUN_ALL_TESTS();
     }
    

    This will run your TEST function when executed.

    To use ctest to actually run your tests you should have the following lines in your cmake file:

    find_package(GTest)
    include_directories(${GTEST_INCLUDE_DIRS})
    
    include(CTest)
    include(GoogleTest)
    
    enable_testing()
    
    target_link_libraries(testName ${GTEST_LIBRARIES})
    
    gtest_discover_tests(testName)
    

    EDIT: As an easier place to start before jumping into cmake, I would recommend you start with compiling and running your command on the command line. You can do that with the following:

    g++ unittest/myunittest.cpp -o unittest/myunittest.out -lgtest -std=c++11
    ./unittest/myunittest.out
    

    Once you know it works, take a look at cmake’s documentation and reproduce your results with a cmake file. Then you can start to scale up your programs. Understanding how to run these commands through the command line will give you an appreciation and a better understanding of what cmake is doing.