Алгоритм драйвера
Алгоритм драйвера предельно прост. Работа драйвера заключается в последовательном считывании входных данных, отправке их тестируемому компоненту, получении результата и сравнении его с ожидаемым результатом. При этом если действительный результат не соответствует ожидаемому, то статус драйвера FAIL. В драйвере также необходимо логировать все результаты, результаты каждой итерации записывать в выходной файл и ее статус. Если результат хоть одной итерации FAIL, то драйвер должен продолжать свою работу. Таким образом мы в конце сможем проанализировать все данные и выявить потенциальные дефекты. Сказанное выглядит примерно так:
Bool script_status = true
Matrix M = GenerateInputData()
For i ß 1 to M.rows do
Result expected = GetExptected(M[i])
Result actual = SendRequest(M[i])
Bool status = Compare(expected, actual)
If status = false
Then sctipt_status = false
LogResult(file,i,actual, expected,status)
LogScriptStatus(script_status)
Функция GenerateInputData() генерирует входные данные. Далее каждая строка из водных данных считывается и посылается тестируемому компоненту. Предварительно мы генерируем ожидаемый результат для данных входных данных и после сравниваем реальный результат с ожидаемым. В лог-файл мы на каждой итерации записываем номер итерации, реальный и ожидаемый результат и статус. Если на какой-то итерации результаты не совпадают, то наш драйвер будет иметь статус FAIL. Для этого мы определим логическую переменную script_status, которую запишем в конец лог-файла.
В качестве примера драйвера и заглушек можно рассмотреть реализацию стека на языке C, причём значения, помещаемые в стек, хранятся не в оперативной памяти, а помещаются в ПЗУ при помощи отдельного модуля, содержащего две функции – записи данных и чтения данных. Формат этих функций таков:
void NV_Read(char *destination, long length, long offset);
void NV_Write(char *source, long length, long offset);
Здесь destination – адрес области памяти, в которую записывается считанное значение, source – адрес области памяти, из которой читается значение, length – длина записываемой области памяти, offset – смещение относительно начального адреса памяти.
Реализация стека с использованием этих функций выглядит следующим образом:
long currentOffset;
void initStack()
{
currentOffset=0;
}
void push(int value)
{
NV_Write((int*)&value,sizeof(int),currentOffset);
currentOffset+=sizeof(int);
}
int pop()
{
int value;
if (currentOffset>0)
{
NV_Read((int*)&value,sizeof(int),currentOffset;
currentOffset-=sizeof(int);
}
}
При выполнении этого кода на реальной системе происходит запись в ПЗУ, однако, если мы хотим протестировать только реализацию стека, изолировав её от реализации модуля работы с памятью, необходимо использовать заглушки вместо реальных функций.
Для имитации работы ПЗУ можно выделить достаточно большой участок оперативной
памяти, в которой и будет производиться запись данных, получаемых заглушкой. Заглушки для функций могут выглядеть следующим образом:
char nvrom[1024];
void NV_Read(char *destination, long length, long offset)
{
printf(“NV_Read called\n”);
memcpy(destination, nvrom+offset, length);
}
void NV_Write(char *source, long length, long offset);
{
printf(“NV_Write called\n”);
memcpy(nvrom+offset, source, length);
}
Каждая из заглушек выводит трассировочное сообщение и перемещает переданное значение в память, эмулирующую ПЗУ (функция NV_Write) или возвращает по ссылке значение, хранящееся в памяти, эмулирующей ПЗУ (функция NV_Read).
Схема взаимодействия тестируемого ПО (функций работы со стеком) с тестовым окружением (драйвером и заглушками функций работы с ПЗУ) изображена на рисунке 29.
Рисунок 29 – Схема взаимодействия тестового окружения и тестируемого ПО