2014-09-10 4 views
1

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

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

Если кто имеет опыт работы с тестированием Say Say вызов стека сказать

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 
} 

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

+0

Почему этот тег C++ при написании кода C? BTW Глобальные переменные - плохая идея. –

+0

. В базе кода есть как C, так и C++. Я знаю, что глобальные переменные - плохая идея. Вот как она была разработана прямо сейчас. Чтобы жить с ней :) –

+0

Тестирование большого/сложного кода НИКОГДА не является простым. Вам нужно написать тесты, которые работают через ваш код, и часто настраивать различные объекты. Там, где я работаю, время для написания тестов часто занимает 2-5-кратное время, необходимое для фактического создания реального кода. Только тогда, когда код для тестирования ДЕЙСТВИТЕЛЬНО прост, это число уменьшается до 1,5 или 2x. Иногда тестовый код может занять более 10 раз первоначальное кодирование. –

ответ

2

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

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; 
} 

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

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

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

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

+0

Следует отметить, что дополнительно группировать связанные глобальные переменные в структуры поможет вам сократить количество параметров, которые необходимо передать вашим функциям. Без этого вы можете легко получить функции с очень большим количеством параметров. –

+0

Еще одна вещь, которую следует учитывать в глобальном закодированном коде, - это «скрытые глобальные переменные» в виде статических переменных функций или локальных переменных потока. –

0

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

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

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

Тогда рассмотрим:

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

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

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

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

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

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

Смежные вопросы