Фреймворк C ++, способный дразнить не виртуальные методы и функции C - PullRequest
4 голосов
/ 17 января 2012

Я знаю, что первая часть этого вопроса была задана ранее , но это было давно :). Мне было интересно, догоняет ли среднее время для какой-либо из сред разработки с открытым исходным кодом Typemock Isolator ++, когда дело доходит до насмешки не виртуальных методов и функций Си. Я в основном интересуюсь gcc под Linux. До сих пор меня интересуют фиктивные средства доступа (чтобы я мог имитировать состояния в имитируемом объекте - см. Ниже) и замена функций C из других библиотек (select, pcap_ * и т. Д.).

class Foo {
  public:
    ...
    bool IsCondition() { return condition; };
    ...
  private:
    bool condition;
}

// I want a framework that allows me to do something like this:
TEST(TestFoo) {
    MOCK_INTERFACE(Foo) mock_foo;
    EXPECT_CALL(mock_foo, IsCondition).returns(true);
    EXPECT(mock_foo.IsCondition()); 
}

Ответы [ 3 ]

5 голосов
/ 17 января 2012

GMock поддерживает так называемое внедрение зависимостей hi-perf для насмешливых не виртуальных методов .

Суть, по ссылке выше, заключается в использовании шаблонов:

template <class PacketStream>
void CreateConnection(PacketStream* stream) { ... }

template <class PacketStream>
class PacketReader {
 public:
  void ReadPackets(PacketStream* stream, size_t packet_num);
};

Затем вы можете использовать CreateConnection () и PacketReader в производственном коде, а также использовать CreateConnection () и PacketReader в тестах.

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

Cxxtest , если вы посмотрите в разделе 8.1 в расширенные функции поддерживает некоторые макросы для упрощения использования / создания интерфейсов:

Из этой ссылки:

CXXTEST_MOCK_GLOBAL( time_t,        /* Return type          */  
                     time,          /* Name of the function */  
                     ( time_t *t ), /* Prototype            */
                     ( t )          /* Argument list        */ );

8.1.2. Mock Functions in Tested Code

Протестированный код использует фиктивные глобальные функции, а не напрямую использует глобальные функции. Вы получаете доступ к фиктивным функциям в пространстве имен T (для теста), поэтому тестируемый код вызывает T :: time () вместо time (). Это эквивалентно использованию абстрактных интерфейсов вместо конкретных классов.

// rand_example.cpp
#include <time_mock.h>

int generateRandomNumber()
{
    return T::time( NULL ) * 3;
}

В прошлом мне повезло с подходом Cxxtest.

0 голосов
/ 24 ноября 2018

При условии, что вы отключаете встраивание и компилируете код, независимый от позиции, ELFSpy поддерживает замену (членских) функций.

Ваш тест можно записать следующим образом

// define alternate implementation for Foo::IsCondition
bool IsConditionTest(Foo*) { return true; }

int main(int argc, char** argv)
{
  // initialise ELFSpy
  spy::initialise(argc, argv);
  // create a handle for intercepting Foo::IsCondition calls
  auto method_spy = SPY(&Foo::IsCondition);
  // relink original method to different implementation
  auto method_fake = spy::fake(method_spy, &IsConditionTest); 
  // capture return value(s) from calls to Foo::IsCondition
  auto returned = spy::result(method_spy);
  // execute your test
  Foo foo;
  bool simulate = foo.IsCondition(); // calls IsConditionTest instead
  // check it worked
  assert(returned.value() == true);
}

Приведенный выше пример эффективно связывает ваш код во время выполнения с вызовом IsConditionTest вместо Foo :: IsCondition, так что вы можете заменить его любым, что захотите. Функции / методы также можно заменить на лямбды.

См. https://github.com/mollismerx/elfspy/wiki для полной информации. Отказ от ответственности: я написал ELFSpy.

0 голосов
/ 17 января 2012

С недавним GCC (например, 4.6), вы можете написать плагин на C или расширение в MELT для этой цели.

Однако, чтобы настроить GCC (с помощью плагина в C или расширения в MELT), вам необходимо частично понять его внутренние представления (Gimple и Tree-s), что занимает время (вероятно, больше недели работы). Так что этот подход имеет смысл, если у вас достаточно большая кодовая база, чтобы стоить усилий.

...