Текстовые данные в юнит тестах
Aug 5, 2018 · CommentsПрограммированиеТестированиеЮнит тесты
В предыдущем посте про табличные юнит тесты я рассказал про способ улучшения читаемости однообразных юнит тестов. Там же мне в комментариях аналогичных примеров из существующих фреймворков накидали. Теперь давайте посмотрим как этот способ сделать еще лучше.
Основная идея была очень проста. Есть повторяющийся, очень монотонный код тестов. Чтобы сделать его читаемым, пишется универсальное тело теста, а все необходимые вариации описываются параметрами. Параметры упаковываются в таблицу, что очень важно для улучшения читаемости. Когда все параметры собраны в одном месте (в пределах одного экрана), анализировать поведение тестируемого кода легче, чем когда параметры разбросаны по файлу длиной в сотни строк.
Как сделать код еще более понятным? К примеру, возьмем таблицу из предыдущего поста. Что с ней не так?
struct {
int x;
int y;
std::string that_thing;
std::string this_key;
bool result;
} const cases[] = {
{0, 0, "thing1", "key2", false},
{0, 1, "thing1", "key2", false},
{0, 2, "thing1", "key2", false},
{0, 3, "thing1", "key1", true },
{1, 0, "thing2", "key1", false},
{1, 1, "thing2", "", false},
{1, 2, "thing2", "", true },
{2, 0, "", "", false},
{2, 1, "", "", true },
{2, 2, "", "", false},
};
В этой таблице слишком много знаков препинания: скобки, запятые, кавычки.
К параметрам в этой таблице неудобно писать комментарии и еще сложнее подружить
удобно выровненные колонки с clang-format
(clang-format off
- это
единственный выход). Более того, столкнувшись с реальностью, подобная таблица
станет еще менее читаемой - колонки вылезут за правый край экрана, выравнивание
будет принесено в жертву более компактной записи и т.д.
В такой ситуации мне нравится записывать данные как простой текст. Сравните:
# Simple cases.
0 0 thing1 key2 false
0 1 thing1 key2 false
0 2 thing1 key2 false
0 3 thing1 key1 true
# Try something harder.
1 0 thing2 key1 false
1 1 thing2 "" false
1 2 thing2 "" true
# This shouldn't break it.
2 0 "" "" false
2 1 "" "" true
2 2 "" "" false
Читать такой текст заметно легче - человеку и без знаков препинания все понятно. Поскольку речь идет о данных для юнит тестов, программист волен выбирать и формат текса, и точность представления данных по своему усмотрению. Легко представить, что в большинстве случаев, данные могут быть представлены в очень простом, но легко читаемом виде.
Чтобы скормить эти данные коду, потребуется написать парсер для текста. Так как формат умышленно выбран простым, его парсер может уложиться буквальнов несколько строк:
std::stringstream data(
R"(
0 0 thing1 key2 false
0 1 thing1 key2 false
0 2 thing1 key2 false
0 3 thing1 key1 true
1 0 thing2 key1 false
1 1 thing2 "" false
1 2 thing2 "" true
2 0 "" "" false
2 1 "" "" true
2 2 "" "" false
)");
while (data.good())
{
int x, y;
std::string thing, key, result;
data >> x >> y >> thing >> key >> result;
if (!data.good())
{
break;
}
std::cout << x << " " << y << " " << thing << " " << key << " "
<< result << "\n";
}
Подобный парсер запросто может быть реализован в виде библиотечной функции, с поддержкой комментариев и разных типов данных.
Текстовые данные также удобны, когда нужно проверить результат, выданный кодом. К примеру, вы хотите убедится что получен ожидаемый заголовок IP пакета. Какой вариант более понятен?
Вариант 1: сравнить заголовок побайтно с ожидаемым заголовком:
const char expected[] = {
'\x45', '\x00', '\x00', '\x3c', '\x17', '\x47', '\x40', '\x00',
'\x40', '\x06', '\xe7', '\xbb', '\xc0', '\xa8', '\x01', '\x92',
'\xad', '\xc2', '\xcb', '\xbc',
};
Вариант 2: распечатать заголовок полученного пакета и сравнить с ожидаемым как текст (игнорируя лишние пробелы):
const std::string expected = R"(
Internet Protocol Version 4, Src: 192.168.1.146, Dst: 173.194.203.188
Differentiated Services Field: 0x00
Total Length: 60
Identification: 0x1747
Flags: 0x02 (Don't Fragment)
Fragment offset: 0
Time to live: 64
Protocol: TCP
Header checksum: 0xe7bb
Source: 192.168.1.146
Destination: 173.194.203.188
)";
Данные в текстовом виде гораздо более понятны чем абстрактный шестнадцатеричный дамп или чем сложная структура, описывающая структуру заголовка с точностью до бита. Соответственно разобраться в таком тесте будет гораздо проще.