Хороші прикладні тестові приклади для вбудованих розробників C [закрито]


20

Я збираюся поговорити зі своїм відділом наступного тижня про тестування одиниць та тестову розробку. В рамках цього я збираюсь показати деякі приклади реального світу з деякого коду, про який я писав недавно, але я також хотів би показати кілька дуже простих прикладів, які я напишу в розмові.

Я шукав в Інтернеті хороші приклади, але намагаюся знайти будь-які, що особливо стосуються нашої сфери розвитку. Майже все програмне забезпечення, яке ми пишемо, - це глибоко вбудовані системи управління, що працюють на невеликих мікроконтролерах. Існує дуже багато коду С, який легко застосувати для тестування одиниць (я буду говорити про тестування одиниць на ПК, а не про саму ціль), доки ви не будете осторонь "нижнього" шару: речі, які говорять безпосередньо до периферійних пристроїв мікроконтролера. Однак більшість прикладів, які я знайшов, базуються на обробці рядків (наприклад, чудовий приклад занурення в ритмові цифри Python), і оскільки ми навряд чи використовуємо рядки, це не дуже підходить (про єдині функції бібліотеки, які зазвичай використовує наш код є memcpy, memcmpі memset,strcat або регулярні вирази не зовсім правильні).

Отже, на питання: будь ласка, будь-хто може запропонувати кілька хороших прикладів функцій, які я можу використати для демонстрації тестування блоку в прямому сеансі? Гарною відповіддю на мою думку (що може змінитись), мабуть, буде:

  • Функція досить проста, щоб зрозуміти будь-хто (навіть ті, хто пише код лише зрідка);
  • Функція, яка не здається безглуздою (тобто відпрацювання паритету чи CRC, ймовірно, краще, ніж функція, що множує два числа разом і додає випадкову константу);
  • Функція, яка досить коротка, щоб писати перед кімнатою людей (я можу скористатися багатьма буферами Vim, щоб зменшити помилки ...);
  • Функція, яка приймає числа, масиви, покажчики або структури як параметри і повертає щось подібне, а не обробку рядків;
  • Функція, яка має просту помилку (наприклад, >а не >=), яку легко ввести, яка все-таки працюватиме в більшості випадків, але порушиться з певним крайовим випадком: легко визначити та виправити за допомогою тесту одиниці.

Будь-які думки?

Хоча це, мабуть, не актуально, самі тести, ймовірно, будуть написані на C ++ за допомогою тестової системи Google: усі наші заголовки вже мають #ifdef __cplusplus extern "C" {обгортку навколо них; це добре працювало з тестами, які я робив до цих пір.


Приймаючи тут «проблему» як розробку презентації, щоб продати TDD для управління, мені здається, це досить добре відповідає бажаному формату. ОП, здається, вимагає існуючих рішень цієї проблеми.
Технофіл

Відповіді:


15

Ось проста функція, яка повинна генерувати контрольну суму над len bytes.

int checksum(void *p, int len)
{
    int accum = 0;
    unsigned char* pp = (unsigned char*)p;
    int i;
    for (i = 0; i <= len; i++)
    {
        accum += *pp++;
    }
    return accum;
}

У ньому є помилка на огорожі: у твердженні for for test має бути тест i < len.

Що цікаво, якщо застосувати його до текстового рядка, як цей ...

char *myString = "foo";
int testval = checksum(myString, strlen(myString));

ви отримаєте "правильну відповідь"! Це тому, що додатковий байт, який був перевірений, був нульовим строковим термінатором. Таким чином, ви можете завершити введення цієї функції контрольної суми в код і, можливо, навіть доставку з нею, і ніколи не помітите проблеми - тобто, поки не почнете застосовувати її до чогось іншого, ніж текстові рядки.

Ось простий модульний тест, який позначить цю помилку (більшість часу ... :-)

void main()
{
    // Seed the random number generator
    srand(time(NULL));

    // Fill an array with junk bytes
    char buf[1024];
    int i;
    for (i = 0; i < 1024; i++)
    {
        buf[i] = (char)rand();
    }

    // Put the numbers 0-9 in the first ten bytes
    for (i = 0; i <= 9; i++)
    {
        buf[i] = i;
    }

    // Now, the unit test. The sum of 0 to 9 should
    // be 45. But if buf[10] isn't 0 - which it won't be,
    // 255/256 of the time - this will fail.
    int testval = checksum(buf, 10);
    if (testval == 45)
    {
        printf("Passed!\n");
    }
    else
    {
        printf("Failed! Expected 45, got %d\n", testval);
    }
}

Дуже добре! Це якраз та відповідь, на яку я сподівався: дякую.
DrAl

Коли ви створюєте буфер, у вас вже є сміття в цьому шматку пам'яті, чи дійсно потрібно ініціалізувати його випадковими числами?
Snake Sanders

@SnakeSanders Я б сказав, що так, оскільки ви хочете, щоб одиничні тести були максимально детермінованими. Якщо компілятор, який ви використовуєте, ставить 0 на свою розробницьку машину, а 10 - на тестову машину, ви будете страшно шукати помилку. Я думаю, що зробити це залежним від часу замість фіксованого насіння є поганою ідеєю з тієї ж причини.
Ендрю каже, що відбудується Моніка

Покладатися на недетерміновану поведінку в одиничному тесті - погана ідея. Тонкий тест доставить вам головні болі рано чи пізно ...
підпишіться

2

Що з реалізацією функції сортування, як сортування міхура ? Після того, як функція сортування запрацює, ви можете продовжити двійковий пошук, який так само добре підходить для тестування одиниць та TDD.

Сортування та пошук залежить від порівняння, яке легко помилитися. Він також включає в себе заміни покажчиків, навколо яких потрібно робити обережно. Обидва схильні до помилок, тому сміливо псуйте :)

Ще кілька ідей:

  • Експерименти дуже допомагають при проведенні рефакторингу. Отже, як тільки ваш сортування бульбашок працює, ви можете змінити його на більш потужний сорт на зразок qsort, і тести все одно повинні пройти, підтверджуючи, що ваша нова функція сортування також працює.
  • Сортування легко перевірити, результат або сортується, або його немає, що робить його хорошим кандидатом.
  • Те саме для пошуку; воно або існує, або його немає.
  • Написання тестів для сортування відкриває дискусії на зразок того, який тип введення використовувати для тесту (нульові елементи, випадкові дані, дублюючі записи, величезні масиви тощо).

Чи є у вас якісь конкретні пропозиції щодо простої помилки, яка б показала, як тестування полегшує життя?
DrAl

@DrAl: Оновив мою відповідь на це.
Мартін Вікман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.