google-tests-conan-sample/readme.md

234 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Базовая настройка тестирования.
## Используемые технологии
- C++11
- CMake
- GTest (Google test framework for C++)
- Conan
## Структура проекта
```
- Project/
-- build/
--- <caches>
--- bin/
---- program
-- include/
--- algos.h
--- algos.c
-- src/
--- main.c
-- tests/
--- test.cpp
-- conanfile.txt
-- CMakeLists.txt
```
## conanfile
Для подключения тестового фреймворка используется система менеджмента артефактов Conan, которая позволяет осуществлять подключение заранее скомпилированных библиотек без необходимости их установки на ОС разработчика. Подключение осуществляется описанием корректных настроек в файле conanfile.txt:
```
[requires]
gtest/cci.20210126
[generators]
cmake
```
Таким образом, будет подключена последняя на момент написания данного документа сборка фреймворка тестирования.
## sources
Исходные коды проекта разделены на две части: собственно исходники и включаемые файлы. Исходники - это код самой программы, использующей алгоритмы, описанные во включаемых заголовочных файлах.
### src/main.c
В файле с программой подключается файл с тестируемым алгоритмом, который используется в коде программы:
```C++
#include <stdio.h>
#include "../include/algos.h"
void swap(char* a, char* b);
int main(int argc, const char** argv) {
char a = -11;
char b = 15;
printf("a=%d; b=%d\n", a, b);
swap(&a, &b);
printf("a=%d; b=%d\n", a, b);
return 0;
}
```
Выводом данного кода будет:
```
user@debian: ./build/bin/prog
a=-11; b=15
a=15; b=-11
```
### include/algos.h
Подключаемый в код программ и тестов заголовочный файл должен содержать только одно объявление функций:
```C++
#ifndef algos
#define algos
void swap(char* a, char* b);
#endif
```
### include/algos.c
файл с реализацией лаконичен:
```C++
#include "algos.h"
void swap(char* a, char* b) {
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
```
## tests
Тесты описываются в отдельном файле, из которого будет собран бинарный файл. Важно, что фреймворк работает только с С++11 или новее, поэтому использовать более старый стандарт не получится, а исходные файлы на С нужно включать в секции `extern "C"`. Каждый тест описывается в специальной макрофункции `TEST` в параметрах которой указывается детальное название теста. В данном примере будет использоваться только один ассерт - `EXPECT_EQ`, который проверяет значение переданной первым аргументом переменной на равенство второму аргументу
### tests/test.cpp
```C++
#include <gtest/gtest.h>
#include <iostream>
extern "C" {
#include "../includes/algos.h"
}
TEST(HelloTest, WeTestHere) {
char a = -11;
char b = 15;
swap(&a, &b);
EXPECT_EQ(a, 15);
EXPECT_EQ(b, -11);
}
TEST(AnotherTest, WeTestThere) {
char a = -11;
char b = -11;
swap(&a, &b);
EXPECT_EQ(a, -11);
EXPECT_EQ(b, -11);
}
```
## CMake
Сборщик CMake описывает правила, по которым будет сформировал Makefile для дальнейшей сборки утилитой GNU Automake или Ninja. В файл настроек необходимо включить строки подключения артефактов Conan, поскольку мы используем готовую сборку фреймворка тестирования, а не устанавливаем его на компьютер. Также в скрипте указывается два исполняемых файла - для сборки программы и тестов, соответственно.
```
cmake_minimum_required(VERSION 3.5)
project(BasicC)
enable_testing()
# GoogleTest requires at least C++11
set(CMAKE_CXX_STANDARD 11)
# conan dependencies
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
# test executable
add_executable(check tests/test.cpp include/algos.h include/algos.c)
target_link_libraries(check ${CONAN_LIBS} gtest_main)
# let make know we use tests
include(GoogleTest)
gtest_discover_tests(check)
# application executable
add_executable(prog src/main.c include/algos.h include/algos.c)
```
## Запуск
Запуск осуществляется из папки `build`, соответственно:
- `conan install ..` (установить зависимости conan, описанные в файле папкой выше)
- `cmake ..` (подготовить Makefile по правилам из файла папкой выше)
- `make`/`ninja` (собрать проект)
- `ctest` (запустить тесты)
- `./bin/prog` (запустить программу)
В результате запуска тестов получится следующий вывод:
```
Test project /home/user/Documents/book-c-basic/build
Start 1: HelloTest.WeTestHere
1/2 Test #1: HelloTest.WeTestHere ............. Passed 0.01 sec
Start 2: AnotherTest.WeTestThere
2/2 Test #2: AnotherTest.WeTestThere .......... Passed 0.00 sec
100% tests passed, 0 tests failed out of 2
Total Test time (real) = 0.01 sec
```
## Сборка артефакта
Данная часть руководства рассматривается в случае, если собранные артефакты не предназначены под конфигурацию Вашей ОС. В качестве примера создаётся артефакт **GTest** под **MinGW**, который отсутствует на данный момент на офф репозиториях **conan center**.
* Инициализация репозитория в папке, где будет находиться скаченный с Интернета проект;
* Скачать **.zip git googletest**;
* Распаковать в папку, где инициализирован репозиторий;
* Создать проект на внутреннем **gitlab** и заремоутить;
* Теперь нужно создать проект тестирования артефакта, **conan** позволяет уже создать готовый **sample package recipe** для тестирования после сборки артефакта;
* Создание рецепта пакета (package recipe) - `conan create . testg/testing`;
* После чего появится следующий проект:
```
- Project/
-- test_package/
--- CMakeLists.txt
--- conanfile.txt
--- example.cpp
-- conanfile.py
```
* Поменять во внешнем файле **conanfile(py)** в методе `source` команды `git clone` ссылку на соответствующий проект, а также следующие изменения в данном файле:
В методе `source` поменять название проекта и путь до CMakeLists.txt:
```python
tools.replace_in_file("hello/CMakeLists.txt", "PROJECT(HelloWorld)",
'''PROJECT(HelloWorld)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()''')
```
На:
```python
tools.replace_in_file("googletest/CMakeLists.txt", "project(googletest-distribution)",
'''project(googletest-distribution)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()''')
```
В методе `build` меняем соурс папку:
```python
def build(self):
cmake = CMake(self)
cmake.configure(source_folder="hello")
cmake.build()
```
На:
```python
def build(self):
cmake = CMake(self)
cmake.configure(source_folder="googletest")
cmake.build()
```
В методе `package` изменить название папки и пути до заголовков:
```python
def package(self):
self.copy("*.h", dst="include", src="hello")
self.copy("*hello.lib", dst="lib", keep_path=False)
self.copy("*.dll", dst="bin", keep_path=False)
self.copy("*.so", dst="lib", keep_path=False)
self.copy("*.dylib", dst="lib", keep_path=False)
self.copy("*.a", dst="lib", keep_path=False)
```
На:
```python
def package(self):
self.copy("*.h", dst="include/gtest", src="googletest/googletest/include/gtest")
self.copy("*gtest.lib", dst="lib", keep_path=False)
self.copy("*.dll", dst="bin", keep_path=False)
self.copy("*.so", dst="lib", keep_path=False)
self.copy("*.dylib", dst="lib", keep_path=False)
self.copy("*.a", dst="lib", keep_path=False)
```
Последний метод будет `package_info`:
```python
def package_info(self):
self.cpp_info.libs = ["hello"]
```
На:
```python
def package_info(self):
self.cpp_info.libs = ["gtest"]
```
* После выполнения настроек **.py** файла можно выполнить - `conan create . testg/testing`;
* Затем, можно выполнить `upload` артефакта и использовать его по мануалу, который описан выше. Лабо можно использовать данный артефакт локально, conan автоматически вначале проверяет cache, и только потом обращается в remote, где указаны соответствующие ссылки (в нашем случае на Nexus).
Также хотелось бы упомянуть один нюанс. Если Вы загружаете уже собранный артефакт, убедитесь, что в файле conan'а настроек конфигураций не были сбиты пути в `[env]` разделе. Была ситуация, когда был загружен артефакт, собранный на ОС GNU Linux, и в данном файле изменились пути под вид данной ОС (C:\MinGW... -> /c/MinGW/).