Я пытаюсь реализовать модульное тестирование на C с помощью Ceedling.
struct Person *list;
/* TASK_FIND_BY */
void test_main_task_find_by_normal(void)
{
char *string = (char *)malloc(sizeof(char));
struct Person new_list_instance;
struct Person *new_list = &new_list_instance;
ask_input_ExpectAndReturn(string);
llist_find_by_ExpectAndReturn(list, string, new_list);
llist_print_Expect(new_list);
llist_remove_all_Expect(&new_list);
printf("\nOutside single: %p\n", new_list);
printf("Outside double: %p\n", &new_list);
task_find_by(list);
}
void task_find_by(struct Person *list)
{
char *input = NULL;
struct Person *new = NULL;
printf("Input exact name/surname/email/phone: ");
input = ask_input();
if (input == NULL) {
printf("Error!");
return;
}
new = llist_find_by(list, input);
if (new != NULL)
llist_print(new);
else
printf("Address not found!\n");
printf("\nInside single: %p\n", new);
printf("Inside double: %p\n", &new);
free(input);
llist_remove_all(&new);
}
Я ожидаю, что функция внутри task_find_by будет вызываться с тем же аргументом, что и здесь: llist_remove_all_Expect(&new_list).
Но фактическая функция вызывается с адресом указателя new, где new содержит new_list. Поскольку new_list и new — разные указатели, их адреса разные. Есть ли способ проверить вызываемый аргумент без изменения реализации функции task_find_by?
- "Outside single: 0x7ffc2e3c03d0"
- "Outside double: 0x7ffc2e3c03c0"
- "Inside single: 0x7ffc2e3c03d0"
- "Inside double: 0x7ffc2e3c0398"
И, пожалуйста, попробуйте создать минимальный воспроизводимый пример, чтобы показать нам. Что это за llist_find_by_ExpectAndReturn «функция»? Это действительно макрос, определяющий переменную list? Что он тогда инициализирует как? Вы уверены, что это не будет делать что-то вроде list = new_list или подобного?
@Someprogrammerdude malloc(sizeof(char)) предназначен только для получения адреса (достаточно одного байта) в куче из-за того, как CMock и моя функция ожидают получить адрес, и это совершенно не относится к делу, и это не делает что нибудь еще. И чтобы ответить на ваш второй комментарий, это макрос, созданный CMock, который представляет собой издевательский интерфейс, включенный в структуру модульного тестирования Ceedling, и весь код внутри test_main_task_find_by_normal(void) имеет отношение к этому вопросу. Обновлено: struct Person *list; определяется как глобальная переменная, которая ничего не содержит.
Если результат этого макроса или функций, которые он вызывает, приводит к чему-то вроде list = new_list, то вы получите ожидаемый результат. Вы пытались запустить код через препроцессор, чтобы увидеть, во что он расширяется? Как насчет того, чтобы использовать отладчик, чтобы увидеть, что на самом деле происходит, и что действительно происходит, и каков может быть результат?
@ryyker Я имею в виду llist_remove_all_Expect(&new_list), где он ожидает &new_list вызова, а в реальной функции он получает &new вызов, где new = new_list
@Someprogrammerdude Да, это действительно ожидаемый результат, и поэтому я спрашиваю, есть ли способ фактически протестировать эту функциональность без изменения реализации функции, которая тестируется модулем. (Возможно, мне не хватает некоторых функций Ceedling или есть обходной путь для проверки адреса)
Возможно, вам просто придется использовать llist_remove_all_ExpectAnyArgs();, поскольку невозможно узнать адрес автоматической переменной new'. Либо так, либо сделайте полный макет обратного вызова для этой функции, которая проверяет содержимое указателя.
Извините, но я в замешательстве. Кажется, что вопрос говорит о том, что поведение отличается от того, что вы ожидали, но в комментариях вы, кажется, говорите, что это так, как ожидалось. Кроме того, мне неясно, что вы подразумеваете под «вызванным аргументом» или какой тест вы хотите выполнить на нем.
Плохо, я хотел сказать, что хочу, а не ожидать, и, поскольку это не работает так, как я хочу, я ищу решение. И я, вероятно, просто выберу решение @pmacfarlane





Поскольку вы не можете знать адрес автоматической переменной new, у вас в основном есть два варианта.
Игнорируйте параметр, который передается llist_remove_all() (но все равно проверяйте, вызывается ли он):
llist_remove_all_ExpectAnyArgs();
Или напишите функцию-заглушку, которая может проверять содержимое указателя, переданного в функцию. Что-то вроде:
static struct Person *expect_person;
static void llist_remove_all_my_stub(struct Person **p, int NumCalls)
{
// Original suggestion
//if (*p != expect_person)
// TEST_FAIL();
// Better suggestion, from someone in comments
TEST_ASSERT_EQUAL_PTR(expect_person, *p);
}
void test_main_task_find_by_normal(void)
{
struct Person new_list_instance;
...
expect_person = &new_list_instance;
llist_remove_all_Stub(llist_remove_all_my_stub);
llist_remove_all_Expect(&new_list);
task_find_by(list);
}
В Unity из фреймворка Ceedling также существует TEST_ASSERT_EQUAL_PTR (ожидаемый_указатель, фактический_указатель), который должен улучшить ясность при тестировании рабочей области, если у кого-то еще есть эта проблема. И спасибо за хороший обходной путь!
Я [хочу], чтобы функция внутри
task_find_byвызывалась с тем же аргументом, что и здесь:llist_remove_all_Expect(&new_list).
Аргумент, который вы передаете последнему, имеет другой тип, чем параметр первого. Эти типы несовместимы, и если сравниваемые значения равны, то это почти наверняка указывает на ошибку в вашем тестовом наборе или в тестируемом коде.
Но фактическая функция вызывается с адресом указателя
new, гдеnewсодержитnew_list.
Если функция получает параметр, равный (struct Person *) &new, то что-то ужасно не так либо с тестами, либо с тестируемым кодом. В task_find_by()new обозначает локальную переменную. Единственный способ, которым его адрес может быть передан в эту функцию в качестве аргумента, — это либо если вызывающий объект использует указатель после окончания времени жизни его референта, либо если передается совершенно дикий указатель.
Возможно, вы имели в виду, что, передав &new_list в качестве аргумента llist_remove_all_Expect(), вы хотите передать new_list в task_find_by(). Это находится в пределах вашего непосредственного контроля.
Или, возможно, вы имели в виду, что хотите, чтобы llist_find_by_ExpectAndReturn(list, string, new_list) установил list равным new_list, в результате чего передача list в task_find_by() эквивалентна поведению, описанному в предыдущем абзаце. Это может быть связано с реализацией llist_find_by_ExpectAndReturn(), и если этого не происходит, то это может быть признаком того, что либо набор тестов, либо тестируемый код имеют недостатки.
Обратите внимание, что
malloc(sizeof(char))выделяют место для одного символа. Это может содержать только пустую строку, нуль-терминатор строки'\0', не более того.