2014-11-17 2 views
0

Мне нужно высмеять функцию, которая имеет аргумент указателя на указатель (таким образом, аргумент **).mock функция с аргументом указателя на указатель

Я попытался somehing ЛИК следующий фрагмент псевдокода (примечание: NON_ZERO_ENUM_MEMBER стоит для перечисления стоимости со значением, не равным 0)

my_arg_type argument; 
argument.enummember = NON_ZERO_ENUM_MEMBER; 

EXPECT_CALL(*my_mock, mock_function(_, _)) 
.times(1) 
.WillOnce(DoAll(SetArgPointee<1>(&argument), Return(0))); 

Это строит ОК, но когда я запускаю мой тест argument.enummember равен 0.

Если я прав, это вызвано тем, что googlemock создает копию того, что я хочу вернуть, и в случае SetArgPointee создайте для него указатель (следовательно, в случае нормального * можно скажем SetArgPointee (аргумент)). Но в этом случае я указываю адрес, и этот адрес превращается в указатель. Но фактическое значение переменной не сохраняется (если мое предположение верно).

Есть ли стандартный способ, с помощью которого googlemock может обрабатывать ** аргументы или мне нужно создать более «глобальную» переменную и вернуть адрес этой переменной?

/редактировать/перемещаемого мой предыдущий редактировать на 2-й ответ, чтобы сохранить оригинальный вопрос короткий

+0

Более глобальное решение переменной работает, но мне все еще интересно, есть ли более приятное решение. – Nemelis

ответ

1

Не видя больше кода, я не могу понять, как ваш argument.enummember становится 0. С тем, что , должно быть возможно установить указатель на аргумент указателя с помощью mock.

Начните с простого класса (аналогично тому, что было отмечено в исходном сообщении).

class argument { 
public: 
    int enummember; 
}; 

Затем создать макет класс, который имеет ложный метод, называемый «прогон», чей аргумент является указателем на указатель.

class Helper { 
public: 
    MOCK_METHOD1(run, int(argument ** a)); 
}; 

Установить некоторые начальные условия

argument * a = new argument; 
a->enummember = 111; 

argument * b = new argument;; 
b->enummember = 222; 

Программа установки ожидания:

// When we call this function, it will set the given argument to b. 
Helper helper; 
EXPECT_CALL(helper, run(_)) 
    .Times(1) 
    .WillOnce(DoAll(SetArgPointee<0>(b), Return(99))); 

Пробег:

int rc = helper.run(&a); 

Вы должны видеть, что RC = 99 и что равна b (они указывают на то же самое адрес).

Это можно проверить, распечатав такие вещи (до и после команды запуска).

std::cout << "a enummember:" << a->enummember << std::endl; 
std::cout << "a (address of the pointer):" << a << std::endl; 

std::cout << "b enummember:" << b->enummember << std::endl; 
std::cout << "b (address of the pointer):" << b << std::endl; 
0

/редактировать/перемещен из первоначального вопроса сюда, чтобы сохранить оригинальный вопрос короткий

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

@ Dan: Я вижу, что ваш ответ в основном сводится к моему «более глобальному» решению, но лучше спорить ;-).На данный момент я не буду устанавливать его как «правильный ответ», так как я хочу увидеть, есть ли с этой дополнительной информацией лучший вариант, но пока никто не считает это правильным ответом.

Некоторые справочную информацию:

  • Код я тестирование равнинно-C, поэтому мои издевается использовать структуры i.s.o. классы.
  • Тип my_arg_type определен в заголовочном-файл, который используется в SUT (тестируемой системы)
  • Для сохранения-вещи-простые: MTBM означает ModuleToBeMocked и ОММ для OtherMockedModule.
  • SUT_code и MTBM/код ОММ является старый существующий код, который я не позволил изменить (не исправить то, что не сломано)

Примечание: Так как на самом деле 2 модуля (даже больше , но это не интересно для этого конкретного вопроса), которые насмехаются в том, что я заменяю имя mock_function сверху пример с MTBM_mock_function, чтобы сделать пример более понятным.

my_arg_type определяется в MTBM.h:

typedef enum 
{ 
    ZERO_ENUM_MEMBER = 0, 
    NON_ZERO_ENUM_MEMBER 
} MTBM_ENUM_TYPE; 

typedef struct 
{ 
    MTBM_ENUM_TYPE enummember; 
    ... //some other members not interesting for our test 
} my_arg_type; 

код моего SUT сводится к:

#include MTBM.h 
#include OMM.h 

int SUT_function_to_be_tested(void) 
{ 
    int error = 0; 
    my_arg_type *argument_ptr = NULL; 
    int interesting_value_OMM = 0; 

    error = SUT_code_which_setups_memory_for_argument_and_initializes_it_to_ZERO_ENUM_MEMBER(argument_ptr); 

    if (error == 0) 
    { 
     error = MTBM_mock_function(TRUE, &argument_ptr) 
    } 

    if ((error == 0) && (argument_ptr->enummember == ZERO_ENUM_MEMBER) 
    { 
     error = OMM_function_not_interesting_for_this_particular_test(); 
    } 

    if ((error == 0) && (argument_ptr->enummember == NON_ZERO_ENUM_MEMBER) 
    { 
     error = OMM_function_interesting_for_this_particular_test(&interesting_value_OMM); 
    } 

    ... 

    return(error); 
} 

Фиктивный Я создал это:

extern "C" 
{ 
    #include MTBM.h 
    #include OMM.h 
} 

struct helper 
{ 
    virtual ~helper() {} 
    virtual int MTBM_mock_function(bool lock, my_arg_type **argument) = 0; 
    virtual int OMM_function_not_interesting_for_this_particular_test(void) = 0; 
    virtual int OMM_function_interesting_for_this_particular_test(int *interesting_value_OMM) = 0; 
}; 

struct Mock: public helper 
{ 
    MOCK_METHOD2(MTBM_mock_function, int(bool lock, my_arg_type **argument)); 
    MOCK_METHOD0(OMM_function_not_interesting_for_this_particular_test, int(void)); 
    MOCK_METHOD1(OMM_function_interesting_for_this_particular_test, int(int *interesting_value_OMM)); 
} 

Mock *my_mock 

extern "C" 
{ 
    int MTBM_mock_function(bool lock, my_arg_type **argument) 
    { 
     my_mock->MTBM_mock_function(lock, argument); 
    } 

    int OMM_function_not_interesting_for_this_particular_test(void) 
    { 
     my_mock->OMM_function_not_interesting_for_this_particular_test(); 
    } 

    int OMM_function_interesting_for_this_particular_test(int *interesting_value_OMM) 
    { 
     my_mock->OMM_function_interesting_for_this_particular_test(interesting_value_OMM); 
    } 
} 

my_mock инициализируется в приборе (см. this previous question для другого unittest, где я определил структуру прибора)

Моя первая попытка (на котором был основан выше вопрос) был:

void setup_mocks(void) 
//There are actually a lot more mocks, but not interesting for this particular question 
//except that I used a function to setup the mocks to keep the actual TEST_F code clear 
{ 
    my_arg_type argument; 
    argument.enummember = NON_ZERO_ENUM_MEMBER; 

    EXPECT_CALL(*my_mock, MTBM_mock_function(_, _)) 
    .times(1) 
    .WillOnce(DoAll(SetArgPointee<1>(&argument), Return(0))); 

    EXPECT_CALL(*my_mock, OMM_function_interesting_for_this_particular_test(_)) 
    .times(1) 
    .WillOnce(DoAll(SetArgPointee<0>(3), Return(0))); 

    //No EXPECT_CALL for the other OMM-function, since that was not expected for this 
    //particular test 

    ... //other mocks, not interesting for this question 
} 

TEST_F(fixture, test_case) 
{ 
    setup_mocks(); 

    SUT_function_to_be_tested(); 
} 

Это неожиданно привело к OMM_function_not_interesting_for_this_particular_test называют и не OMM_function_interesting_for_this_particular_test.

Как я могу понять, что это связано с тем, как GoogleMock устанавливает макет, следовательно, моя ссылка на «более глобальную переменную», поэтому в то же время я изменил код на:

void setup_mocks(my_arg_type *argument) 
{ 
    argument->enummember = NON_ZERO_ENUM_MEMBER; 
    EXPECT_CALL(*my_mock, MTBM_mock_function(_, _)) 
    .times(1) 
    .WillOnce(DoAll(SetArgPointee<1>(&*argument), Return(0))); 

    ... 

} 

TEST_F(fixture, test_case) 
{ 
    my_arg_type argument; 

    setup_mocks(&argument); 

    SUT_function_to_be_tested(); 
} 

и это работает, но мне было интересно, если есть способ, чтобы избежать «более глобального» решения и сделать это непосредственно через GoogleMock (например, определить свой собственный тип действия (с которым у меня нет какого-либо опыт вообще)?). Поскольку этот конкретный шаблон с указателем на указатель, который нужно высмеять среди множества других функций, которые нужно издеваться, необходимо для большего количества unittests. И я хочу избежать этого в будущем, мне нужно создать функции setup_mock с несколькими аргументами, чтобы установить несколько указателей на указатели на указатели.

+1

Проблема с использованием void setup_mocks (void); - то, что локальная переменная аргумент my_type_argument; больше не находится в области действия после того, как вы вернетесь из функции. Назначение указателя на адрес этой переменной не определено. – Dan

+0

Я тоже нашел это.Хотел, чтобы GoogleMock сделал глубокий отпечаток всего аргумента i.s.o. просто копия «значения» аргумента (= мелкая-копия). Но чем еще раз, как GoogleMock может знать, что аргумент - это то, для чего нужна глубокая копия ... Лишает мое текущее решение и/или определяет действие пользователя (с которым у меня нет опыта, поэтому, если кто-то знает хороший учебник/пример для этого, я бы это утвердил). – Nemelis

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