Confusion about unit tests (googletest) and projects/folder/files
Asked Answered
A

2

2

It's the first time I want to use unit tests in my c++ project. Hence I've many existing classes for which I will write tests (at least for some of them). Further, the application has of course a main() function.

I'm using qt creator with qmake but could also switch to cmake. The project, qt creator and qmake are working nicely.

My confusion is now how do I add unit test? I intent to use googletest. I've already run a test in a new project, testing some dummy add(int, int) function, with everything in one file (function, tests and main). How does that work with an existing project (which has it's own main()). Do I need to setup a second project and include the headers in the test files? What is a good folder structure for that?

Affectation answered 26/1, 2017 at 22:7 Comment(2)
One simple way is to create a lib, your application will "only" have the main, it will call class/function of the lib normally. Then your Test application can also link to your lib and test its components. (For a total of 3 projects: MyLib, MyApp, MyTest).Fecundate
It's definitely best if your tests are in a second project. This project (which I'm the author of) has gtest incorporated through CMake, you can literally copy/paste the CMake files to get off the ground, and see an example of the folder structure.Bealle
O
2

In my opinion the best approach is to create a model library (with all the production code), a program executable and a test executable. Then you can link all your production code against the program and test executable. The test-files are also stored in the test executable. All my projects have this structure:

model.lib (link against both exe)
program.exe
modelTest.exe

In the concrete folder on your file system can be stored the test- and production-files. A build tool (like cmake) should separate the files and put the test files into the test executable and the production files into the model-library.

Consider the following example: I have a folder with the following files:

src (folder)
 - main.cpp
 - model.h
 - model.cpp
 - modelTest.cpp

A cmake file could look like this:

cmake_minimum_required(VERSION 2.8)
project(TheUltimateProject)
ADD_EXECUTABLE(program main.cpp)
ADD_library(model shared model.cpp model.h)
ADD_EXECUTABLE(modelTest modelTest.cpp)

target_link_libraries(program model)
target_link_libraries(modelTest model)

If you use a testing-framework like google test, you also have to link the modelTest executable against gmock and don't forget to add the include folder:

e.g.

link_directories($ENV{GMOCK_HOME}/Debug)
include_directories($ENV{GMOCK_HOME}/googlemock/include) 
include_directories($ENV{GMOCK_HOME}/googletest/include)
target_link_libraries(modelTest gmock_main gmock)
Ot answered 30/1, 2017 at 15:31 Comment(0)
C
0

Let's assume you have already installed CMake and the Google Test framework in your system.

I hope the following simple example will help to find an appropriate solution.

The example's files structure:

├── CMakeLists.txt
├── converter
├── converterTests
└── Src
    ├── Converter
    │   ├── Headers
    │   │   └── converter.hpp
    │   └── Sources
    │       └── converter.cpp
    ├── main.cpp
    └── Tests
        ├── CMakeLists.txt
        ├── gTestsMain.cpp
        ├── Headers
        └── Sources
            └── converterTests.cpp

CMakeLists.txt

cmake_minimum_required( VERSION 3.11 )

project( converter VERSION 0.1.0 )

set( CMAKE_CXX_STANDARD 20 )

set( SOURCE_FILES 
    Src/main.cpp
    Src/Converter/Sources/converter.cpp
)

include_directories( 
    Src/Converter/Headers/
)

add_executable( ${PROJECT_NAME} ${SOURCE_FILES} )


##########
# GTests
##########

add_subdirectory(Src/Tests)

Src/main.cpp

#include "converter.hpp"

#include <iostream>
#include <iomanip>


int main()
{
    std::string start_date{"23102014"};

    std::cout 
        << std::endl
        << "Converting DDmmYYYY to YYmmDD" 
        << std::endl
        << std::endl
        << "Result of converting " 
        << std::quoted(start_date) 
        << " : " 
        << std::quoted(*date::DdMmYyyyDateToYyMmDd(start_date)) 
        << std::endl
        << std::endl;
}

Src/Converter/Headers/converter.hpp

#pragma once

#include <memory>
#include <string>


namespace date
{
    std::shared_ptr<std::string> DdMmYyyyDateToYyMmDd(const std::string& dd_mm_yyyy_date);
}

Src/Converter/Sources/converter.cpp

#include "converter.hpp"


namespace date
{
    std::shared_ptr<std::string> DdMmYyyyDateToYyMmDd( const std::string& dd_mm_yyyy_date )
    {
        // e.g. 20102014 to 141020 or DDmmYYYY to YYmmDD

        if ( dd_mm_yyyy_date.size() < std::string("20102014").size() ) 
        {
            return nullptr;
        }

        std::string yy_mm_dd_date = dd_mm_yyyy_date.substr(0, 2);

        yy_mm_dd_date.insert(0, dd_mm_yyyy_date.substr(2, 2));

        yy_mm_dd_date.insert(0, dd_mm_yyyy_date.substr(6));

        return std::make_shared<std::string>(yy_mm_dd_date);
    }
}

Src/Tests/CMakeLists.txt

cmake_minimum_required( VERSION 3.11 )

set( TEST_SOURCE_FILES
    gTestsMain.cpp
    Sources/converterTests.cpp

    ../Converter/Sources/converter.cpp
    ../Converter/Headers/converter.hpp
)

add_executable(converterTests ${TEST_SOURCE_FILES})

target_link_libraries(converterTests gtest gmock pthread)

Src/Tests/gTestsMain.cpp

#include <gtest/gtest.h>
#include <gmock/gmock.h>


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

Src/Tests/Sources/converterTests.cpp

#include "converter.hpp"

#include <gtest/gtest.h>


TEST(ConverterTestSuite, empty_date)
{
    ASSERT_EQ( date::DdMmYyyyDateToYyMmDd( std::string( "" ) ), nullptr );
}

TEST(ConverterTestSuite, date_convert)
{
    std::string start_date{"30122045"};

    ASSERT_EQ( *date::DdMmYyyyDateToYyMmDd( start_date ), std::string("451230") );
}

Execution of converterTests will print:

[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from ConverterTestSuite
[ RUN      ] ConverterTestSuite.empty_date
[       OK ] ConverterTestSuite.empty_date (0 ms)
[ RUN      ] ConverterTestSuite.date_convert
[       OK ] ConverterTestSuite.date_convert (0 ms)
[----------] 2 tests from ConverterTestSuite (0 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 1 test suite ran. (1 ms total)
[  PASSED  ] 2 tests.
Corymb answered 3/8, 2022 at 10:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.