Программирование. Принципы и практика использования C++ Исправленное издание, стр. 372
Если вы представите себе десятки тестов, то почувствуете огромную разницу. При тестировании реальных систем мы часто должны проверить многие тысячи тестов, поэтому знать, какой из них закончился неудачей, очень важно.
Прежде чем идти дальше, отметим еще один пример (полуформальный) методики тестирования: мы тестировали правильные значения, иногда выбирая их из конца последовательности, а иногда из середины. Для данной последовательности мы можем перебрать все ее значения, но на практике сделать это нереально. Для тестов, ориентированных на провал, выбираем одно значение в каждом из концов последовательности и одно в середине. И снова следует отметить, что этот подход не является систематическим, хотя он демонстрирует широко распространенный образец, которому можно следовать при работе с последовательностями или диапазонами значений.
Какими недостатками обладают указанные тесты?
• Один и тот же код приходится писать несколько раз.
• Тесты пронумерованы вручную.
• Вывод минимальный (мало информативный).
Поразмыслив, мы решили записать тесты в файл. Каждый тест должен иметь идентифицирующую метку, искомое значение, последовательность и ожидаемый результат. Например:
{ 27 7 { 1 2 3 5 8 13 21} 0 }Это тест под номером
277{ 1,2,3,5,8,13,21 }0falsestruct Test { string label; int val; vector<int> seq; bool res;};istream& operator>>(istream& is, Test& t); // используется описанный // форматint test_all(istream& is){ int error_count = 0; Test t; while (is>>t) { bool r = binary_search( t.seq.begin(), t.seq.end(), t.val); if (r !=t.res) { cout << "отказ: тест " << t.label << "binary_search: " << t.seq.size() << "элементов, val==" << t.val << " –> " << t.res << '\n'; ++error_count; } } return error_count;}int main(){ int errors = test_all(ifstream ("my_test.txt"); cout << "Количество ошибок: " << errors << "\n";}Вот как выглядят некоторые тестовые данные.
{ 1.1 1 { 1 2 3 5 8 13 21 } 1 }{ 1.2 5 { 1 2 3 5 8 13 21 } 1 }{ 1.3 8 { 1 2 3 5 8 13 21 } 1 }{ 1.4 21 { 1 2 3 5 8 13 21 } 1 }{ 1.5 –7 { 1 2 3 5 8 13 21 } 0 }{ 1.6 4 { 1 2 3 5 8 13 21 } 0 }{ 1.7 22 { 1 2 3 5 8 13 21 } 0 }{ 2 1 { } 0 }{ 3.1 1 { 1 } 1 }{ 3.2 0 { 1 } 0 }{ 3.3 2 { 1 } 0 }Здесь видно, почему мы использовали строковую метку, а не число: это позволяет более гибко нумеровать тесты с помощью десятичной точки, обозначающей разные тесты для одной и той же последовательности. Более сложный формат тестов позволяет исключить необходимость повторения одной и той же тестовой последовательности в файле данных.
26.3.2.3. Случайные последовательности
Существует один прием, который иногда помогает решить эту проблему: просто сгенерировать много случайных значений. Например, ниже приведена функция, которая записывает описание теста в поток
coutrandint()std_lib.facilities.hvoid make_test(const string& lab,int n,int base,int spread) // записывает описание теста с меткой lab в поток cout // генерирует последовательность из n элементов, начиная // с позиции base // среднее расстояние между элементами равномерно распределено // на отрезке [0, spread]{ cout << "{ " << lab << " " << n << " { ";