Использование Google mock для кода C

Я поддерживаю унаследованный проект, написанный на C, и это невозможно сделать, чтобы он работал с компилятором С++. Поскольку код перекрестно скомпилирован, однако можно запускать модульные тесты или аналогичные в среде хоста. поэтому он также может взаимодействовать с компилятором хоста С++ и использовать google-test и google-mock.

Существуют определенные возможности google-mock, которые кажутся очень заманчивыми для использования для тестирования в качестве вызова реальных реализаций и установки ожиданий вызова.

Я хотел бы иметь возможность использовать их в коде C. Я вижу, что действительно возможно использовать google-mock без использования vtables, но для этого требуются шаблоны.

Есть ли способ издеваться над открытыми функциями C с помощью Google Mock?

Ответы

Ответ 1

Я нашел способ иметь возможность издеваться над голографическими функциями C в google-mock.

Решение состоит в том, чтобы объявить foobar слабым псевдонимом, который сопоставляется с foobarImpl. В производственном коде вы не реализуете foobar(), а для модульных тестов вы предоставляете реализацию, которая вызывает статический макет.

Это решение является специфичным для GCC, но существуют и другие компиляторы/линкеры, которые обеспечивают слабую наложение.

  • переименуйте функцию void foobar(); в void foobarImpl();
  • добавить атрибут к функции foobar как: void foobar() __attribute__((weak, alias("foobarImpl") ));
  • если вы хотите иметь слабый псевдоним, используйте директиву preproessor для удаления слабых из атрибутов.

Следовательно:

#pragma once
void foobar();

становится

// header.h
#pragma once

void foobar();    
void foobarImpl(); // real implementation

и

extern "C" {
#include "header.h"
}
// code.c
void foobarImpl() {
  /* do sth */
}
void foobar() __attribute__(( weak, alias ("foobarImpl") )); // declare foobar to be a weak alias of foobarImpl

Это позволит компоновщику gnu связывать вызовы foobar() с foobarImpl() всякий раз, когда символ foobar()

отсутствует,

затем добавьте тестовый код

struct FooInterface {
   virtual ~FooInterface() {}
   virtual void invokeFoo() const { }
};

class MockFoo : public FooInterface {
public:
  MOCK_CONST_METHOD0(invokeFoo, void());
}

struct RealFoo : public FooInterface {
   virtual ~RealFoo() {}
   virtual void invokeFoo() const { foobarImpl(); }
};

MockFoo mockFoo;
RealFoo realFoo;
void foobar() {
  mockFoo.invokeFoo();
}

если этот код скомпилирован и связан, он заменит foobar макетным вызовом. если вы действительно хотите вызвать foobar(), вы все равно можете добавить вызов по умолчанию.

ON_CALL(mockFoo, invokeFoo())
       .WillByDefault(Invoke(&realFoo,&RealFoo::invokeFoo));

Ответ 2

Как из часто задаваемых вопросов в Google Mock:

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

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

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

Ответ 3

В вашем вопросе конкретно упоминается Google Mock, но при этом не указывается какая-либо другая причина для использования этой структуры. Другой ответ предполагает использование обходного пути, который кажется излишне навязчивым.

Следовательно, я надеюсь, что мне позволено сделать альтернативное предложение, которое хорошо работает, не используя слабые псевдонимы и т.д.

Я использовал CppUTest (https://cpputest.github.io/) для unit test с помощью mock, успешно на нескольких крупных проектах в основном-C ( некоторые С++). Издевательские работы, не прибегая к какой-либо уловке вышеупомянутого вида.

К сожалению, проектная документация немного слаба, а некоторые лучше (если немного гибко-доктринер) информация и примеры в книге (также рассматривается как циркуляр в формате PDF) "Test Driven Development for Embedded C" - Джеймс W Greening (ISBN -13: 978-1-934356-62-3)