it-swarm.com.ru

Без насмешек функция

Я застрял в проблеме и не могу найти решение.

Я использую VS2005 SP1 для компиляции кода.

У меня есть глобальная функция:

A* foo();

У меня фальшивый класс

class MockA : public A {
public:
    MOCK_METHOD0 (bar, bool());
    ...
};

В источниках он доступен следующим образом: foo()->bar(). Я не могу найти способ высмеять это поведение. И я не могу изменить источники, поэтому решение в Google Mock Cookbook не может быть и речи.

Любая помощь или указатели в правильном направлении будут высоко оценены. :)

9
Muhammad Hassan

Нет, это невозможно без изменения исходных кодов или создания собственной версии foo(), связанной с исполняемым кодом.


От GoogleMock's FAQ это говорит

Мой код вызывает статическую/глобальную функцию. Могу ли я высмеивать это?

Вы можете, но вам нужно внести некоторые изменения.

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

Этот блог тестирования Google сообщение говорит это превосходно. Проверьте это.

Также из Кулинарная книга

Насмешливые бесплатные функции

Можно использовать Google Mock, чтобы смоделировать свободную функцию (то есть функцию в стиле C или статический метод). Вам просто нужно переписать свой код, чтобы использовать интерфейс (абстрактный класс).

Вместо непосредственного вызова свободной функции (скажем, OpenFile), представьте для нее интерфейс и получите конкретный подкласс, который вызывает свободную функцию:

class FileInterface {
 public:
  ...
  virtual bool Open(const char* path, const char* mode) = 0;
};

class File : public FileInterface {
 public:
  ...
  virtual bool Open(const char* path, const char* mode) {
    return OpenFile(path, mode);
  }
};

Ваш код должен общаться с FileInterface, чтобы открыть файл. Теперь легко смоделировать функцию.

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

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


Как вы упомянули в своем комментарии, что вы фактически предоставляете свою собственную версию foo(), вы можете легко решить эту проблему, имея глобальный экземпляр другого фиктивного класса:

struct IFoo {
    virtual A* foo() = 0;
    virtual ~IFoo() {}
};

struct FooMock : public IFoo {
     FooMock() {}
     virtual ~FooMock() {}
     MOCK_METHOD0(foo, A*());
};

FooMock fooMock;

// Your foo() implementation
A* foo() {
    return fooMock.foo();
}

TEST(...) {
    EXPECT_CALL(fooMock,foo())
        .Times(1)
        .WillOnceReturn(new MockA());
    // ...
}

Не забудьте очистить все ожидания вызовов после каждого запуска теста.

14
πάντα ῥεῖ

Конечно, ответ, объясняющий решение в соответствии с документацией GTest/GMock, не может быть намного более правильным.

Но я хотел бы добавить временный быстрый и грязный подход. Это должно быть применимо к случаям, когда вы хотите получить тестируемый устаревший код C/C++ максимально быстро и неинвазивно. (Просто приступить к исправлениям, рефакторингу и более правильному тестированию как можно скорее после этого.)

Итак, чтобы смоделировать свободную функцию void foo(int), появляющуюся в некотором тестируемом коде, в исходном файле вы просто вносите следующие изменения:

#if TESTING
#define foo(param) // to nothing, so calls to that disappear
#endif

// ... code that calls foo stays untouched and could be tested

Макрос TESTING, указывающий, что тестируемый код выполняется, не поставляется с GTest/GMock - его нужно добавить для целей тестирования самостоятельно.

Возможности довольно ограничены, но вы также можете создать что-то полезное для возвращаемых типов как A* в примере вопроса.

К сожалению, это также не решение без изменения кода . Если это действительно необходимо, вы можете воспользоваться Google для «швов ссылок». Но я предполагаю, что на практике это может быть довольно хлопотно. И даже во многих/большинстве случаев это вообще может оказаться невозможным ?!

0
yau