/редактировать/перемещен из первоначального вопроса сюда, чтобы сохранить оригинальный вопрос короткий
По запросу еще информация (я не имею права давать точный код, так что я должен придерживаться псевдо-реализация). Сначала я хотел избежать этого (как вы можете видеть), это делает мой вопрос довольно длинным ;-))
@ 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 с несколькими аргументами, чтобы установить несколько указателей на указатели на указатели.
Более глобальное решение переменной работает, но мне все еще интересно, есть ли более приятное решение. – Nemelis