Литмир - Электронная Библиотека
A
A

Вернемся к нашей функции, вычисляющей площадь прямоугольника (см. раздел 5.6.1).

// Вычисляет площадь прямоугольника;

// если аргументы неправильные, генерирует исключение Bad_area

int area(int length, int width)

{

  if (length<=0 || width <=0) throw Bad_area();

    return length*width;

}

Эта функция проверяет предусловия, но они не сформулированы в виде комментариев (для такой короткой функции это вполне допустимо), и считается, что все вычисления проводятся корректно (для таких простых вычислений это также вполне приемлемо). И тем не менее эту функцию можно было написать намного яснее.

int area(int length, int width)

// Вычисляет площадь прямоугольника;

// предусловия: аргументы length и width являются положительными

// постусловия: возвращает положительное значение, являющееся

// площадью

{

  if (length<=0 || width <=0) error("area() pre-condition");

  int a = length*width;

  if (a<=0) error("area() post-condition");

  return a;

}

Мы не можем проверить выполнение всех постусловий, но можем проверить их часть, убедившись, что возвращаемое число является положительным.

ПОПРОБУЙТЕ

Найдите пару значений, при которых предусловие выполняется, а постусловие — нет.

Пред- и постусловия обеспечивают проверку логичности кода. Они тесно связаны с понятиями инвариантов (раздел 9.4.3), корректности (разделы 4.2 и 5.2), а также с тестированием (глава 26).

5.11. Тестирование

Как определить, когда следует остановить отладку? Ясно, что отладка должна идти до тех пор, пока не будут выявлены все ошибки, — или нам так покажется. А как узнать, что мы нашли последнюю ошибку? Мы не знаем. Последняя ошибка — это шутка программистов. Такой ошибки не существует. В большой программе никогда невозможно найти последнюю ошибку.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Кроме отладки, нам необходим систематический подход к поиску ошибок. Он называется тестированием (testing) и рассматривается в разделе 7.3, упражнениях к главе 10 и в главе 26. В принципе тестирование — это выполнение программы с большим и систематически подобранным множеством входных данных и сравнение результатов с ожидаемыми. Выполнение программы с заданным множеством входных данных называют тестовым вариантом (test case). Для реальных программ могут потребоваться миллионы тестовых вариантов. Тестирование не может быть ручным, когда программист набирает варианты тест за тестом, поэтому в последующих главах мы рассмотрим инструменты, необходимые для правильного тестирования.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Тем временем напомним, что тестирование основано на убеждении, что поиск ошибок выполняется правильно. Рассмотрим пример.

Точка зрения 1. Я умнее любой программы! Я могу взломать код @#$%^!

Точка зрения 2. Я вылизывал эту программу две недели. Она идеальна!

Как вы думаете, кто из этих двух программистов найдет больше ошибок? Разумеется, наилучшим вариантом является опытный программист, придерживающийся первой точки зрения и спокойно, хладнокровно, терпеливо и систематически работающий над ошибками. Хорошие тестировщики на вес золота!

Мы стараемся систематически выбирать тестовые варианты и всегда проверять правильные и неправильные входные данные. Первый пример будет приведен в разделе 7.3.

Задание

Ниже приведены двадцать пять фрагментов кода. Каждый из них должен быть впоследствии вставлен в определенное место программы.

#include "std_lib_facilities.h"

int main()

try {

  << здесь будет ваш код >>

  keep_window_open();

  return 0;

}

catch (exception& e) {

  cerr << "error: " << e.what() << '\n';

  keep_window_open();

  return 1;

}

catch (…) {

  cerr << "Ой: неизвестное исключение !\n";

  keep_window_open();

  return 2;

}

В некоторых из них есть ошибки, а в некоторых — нет. Ваша задача — найти и устранить все ошибки. Устранив эти ошибки, скомпилируйте программу, выполните ее и выведите на экран слово “Success!”. Даже если вы считаете, что нашли все ошибки, вставьте в программу исходный (неисправленный) вариант и протестируйте его; может быть, ваша догадка об ошибке была неверной или во фрагменте их несколько. Кроме того, одной из целей этого задания является анализ реакции компилятора на разные виды ошибок. Не набирайте эти фрагменты двадцать пять раз — для этого существует прием “copy–paste”. Не устраняйте проблемы, просто удаляя инструкции; исправляйте их, изменяя, добавляя или удаляя символы.

1. cout << "Success!\n";

2. cout << "Success!\n;

3. cout << "Success" << !\n"

4. cout << success << endl;

5. string res = 7; vector<int> v(10); v[5] = res; cout << "Success!\n";

6. vector<int> v(10); v(5) = 7; if (v(5)!=7) cout << "Success!\n";

7. if (cond) cout << "Success!\n"; else cout << "Fail!\n";

8. bool c = false; if (c) cout << "Success!\n"; else cout << "Fail!\n";

9. string s = "ape"; boo c = "fool"<s; if (c) cout << "Success!\n";

72
{"b":"847443","o":1}