Gtest с большой кодовой базой на C и C ++

Я нахожусь в проекте, где у нас есть большая кодовая база, и в настоящее время у нее вообще нет модульных тестов. Код, над которым мы работаем, будет, наконец, выполняться на коробке, которая действует как коммутатор / маршрутизатор / межсетевой экран.

Поэтому я работаю над фрагментом кода, который должен быть проверен модулем с помощью Gtest.
проблема, с которой я сталкиваюсь, заключается в том, что я проверяю переменные, чтобы проверить саму функцию.
Например, у меня есть функция, которая использует как 4 указателя на разные объекты и использует пару глобальных переменных. Чтобы протестировать разные пути в коде, мне нужно инициализировать почти все состояние машины / значения зависимых переменных.
В дополнение к сложности, как это верно для большой кодовой базы, эта функция / метод, который я написал, использует множество других процедур / методов, которые также необходимо протестировать. Каждый из них должен быть также протестирован, и каждый из них имеет свои собственные зависимости.
Я не уверен, правильно ли я подхожу к проблеме, или это тот случай, когда gtest может оказаться неподходящим инструментом для тестирования такой большой базы кода.

Если у кого-то есть опыт, скажем, тестирования, скажем, стека вызовов скажем

function A {
code
code
function B
code
code
function C
code
}

function B
{
function D
code
function E
}

function C{
code
function F
function G
code
}

как то так. Как мне проверить все эти функции A-F ?? Что такое хорошая стратегия?

1

Решение

Во-первых, рефакторинг кода, чтобы тестируемые части были изолированы. В частности, это означает удаление доступа к глобалам. Пример:

int global;
int function() {
int r = foo();
global += r / 2;
bar(r);
return 42;
}

Удаление глобального объекта означает преобразование его во входной параметр:

int real_function(int* target) {
assert(target);
int r = foo();
*target += r / 2;
bar(r);
return 42;
}

Тогда, конечно, оставшийся код перестанет компилироваться, поэтому вы добавляете ключ обратной совместимости:

int global_bar;
// @deprecated, use real_function() directly
int function() {
return real_function(&global_bar);
}

Используя это, вы увеличиваете цепочку вызовов, извлекая зависимости и, надеюсь, однажды удаляете последний вызов варианта, который требует глобальные переменные. А пока вы можете писать тесты для функций, которые больше не зависят от глобальных вещей. Обратите внимание, что для C ++ вы должны использовать ссылки вместо указателей и, вероятно, передавать необходимые внешние объекты в конструктор класса. Это также называется внедрением зависимостей. Обязательно изучите этот термин для полного понимания.

Другой способ проверки функций, затрагивающих глобальные переменные, состоит в том, чтобы использовать функцию настройки теста, чтобы сбросить глобальное в известное состояние. Это все еще требует связывания в глобальном, хотя, что может оказаться трудным. А если не использовать глобальные переменные, это может значительно улучшить кодовую базу, поэтому принятие этого сообщения также приводит к неверному сообщению.

2

Другие решения

Ульрих Экхардт, по сути, говорит: «Вы должны избавиться от глобальных переменных, чтобы сделать легко тестируемый код». Но вы действительно должны идти дальше.

Для любой глобальной функции, которую вы хотите проверить, вы должны посмотреть на

  • Глобалы, к которым он обращается.
  • Параметры, которые он использует.
  • функции, которые он вызывает.

Тогда подумайте:

  • Преобразование вызываемых функций в вызовы одного или нескольких интерфейсов и передача их в качестве параметров.
  • Преобразование глобальных параметров в параметры или вызовы функций в интерфейсе.

Если ваша функция является функцией объекта, а не глобальной функцией, вы можете рассмотреть дополнительно:

  • создание глобальных переменных-членов и передача их конструктору
  • делая функции, которые он вызывает виртуальные функции-члены

Последнее, что я хотел бы рассмотреть, чтобы сделать функцию тестируемой, относится ли она к классу.

После того, как все это решено, вы можете легко смоделировать нужные биты. Если вы используете gtest, вы можете использовать gmock, чтобы сделать это проще. (Я использовал gmock с gtest и раньше, и он довольно безболезненный.)

(И да, я использовал этот подход на больших базах кода раньше … обычно довольно больно начинать с него, но как только вы привыкните к нему и код станет более тестируемым — все улучшится.)

0

По вопросам рекламы [email protected]