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

  }

  else if (x>0) {

    if (y<0)

      cout << "Большое положительное число \n";

    else

      cout << "Положительное число \n";

  }

}

Наиболее очевидная ошибка в этом фрагменте заключается в том, что мы забыли о варианте, в котором переменная

x
равна нулю. Сравнивая числа (положительные или отрицательные) с нулем, программисты часто забывают о нем или приписывают неправильной ветви (например, относят его к отрицательным числам). Кроме того, существует более тонкая (хотя и распространенная) ошибка, скрытая в этом фрагменте: действия при условиях (
x>0 && y<0
) и (
x>0 && y>=0
) каким-то образом поменялись местами. Это часто случается, когда программисты пользуются командами “копировать и вставить”.

Чем более сложными являются варианты использования инструкций

if
, тем вероятнее становятся ошибки. Тестировщики анализируют такие коды и стараются не пропустить ни одной ветви. Для функции
do_branch1()
набор тестов очевиден.

do_branch1(–1,–1);

do_branch1(–1, 1);

do_branch1(1,–1);

do_branch1(1,1);

do_branch1(–1,0);

do_branch1(0,–1);

do_branch1(1,0);

do_branch1(0,1);

do_branch1(0,0);

По существу, это наивный подход “перебора всех альтернатив”, которой мы применили, заметив, что функция

do_branch1()
сравнивает значения с нулем с помощью операторов
<
и
>
. Для того чтобы выявить неправильные действия при положительных значениях переменной
x
, мы должны объединить вызовы функции с желаемыми результатами.

Обработка инструкций

switch
аналогична обработке инструкций
if
.

void do_branch1(int x, int y)  // плохая функция

 // неправильное использование инструкции switch

{

  if (y<0 && y<=3)

  switch (x) {

  case 1:

    cout << "Один\n";

    break;

  case 2:

    cout << "Два\n";

    case 3:

  cout << "Три\n";

  }

}

Здесь сделаны четыре классические ошибки.

• Мы проверяем значения неправильной переменной (

y
, а не
x
).

• Мы забыли об инструкции

break
, что приводит к неправильному действию при
x==2
.

• Мы забыли о разделе

default
(считая, что он предусмотрен инструкцией
if
).

• Мы написали

y<0
, хотя имели в виду
0<y
.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Как тестировщики мы всегда ищем непредвиденные варианты. Пожалуйста, помните, что просто устранить проблему недостаточно. Она может возникнуть снова, когда мы ее не ожидаем. Мы хотим писать тесты, которые систематически выявляют ошибки. Если мы просто исправим этот простой код, то можем либо неправильно решить задачу, либо внести новую ошибку. Цель анализа кода заключается не только в выявлении ошибок (хотя это всегда полезно), а в разработке удобного набора тестов, позволяющих выявить все ошибки (или, говоря более реалистично, большинство ошибок).

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Подчеркнем, что циклы всегда содержат неявные инструкции if: они выполняют проверку условия выхода из цикла. Следовательно, циклы также являются инструкциями ветвления. Когда мы анализируем программы, содержащие инструкции ветвления, первым возникает следующий вопрос: все ли ветви мы проверили? Удивительно, но в реальной программе это не всегда возможно (потому что в реальном коде функции вызываются так, как удобно другим функциям, и не всегда любыми способами). Затем возникает следующий вопрос: какую часть кода мы проверили? И в лучшем случае мы можем ответить: “Мы проверили большинство ветвей”, объясняя, почему мы не смогли проверить остальные ветви. В идеале при тестировании мы должны проверить 100% кода.

26.3.4. Системные тесты

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Тестирование любой более или менее значимой системы требует опыта. Например, тестирование компьютеров, управляющих телефонной системой, проводится в специально оборудованных комнатах с полками, заполненными компьютерами, имитирующими трафик десятков тысяч людей. Такие системы стоят миллионы долларов и являются результатом работы коллективов очень опытных инженеров. Предполагается, что после их развертывания основные телефонные коммутаторы будут непрерывно работать двадцать лет, а общее время их простоя составит не более двадцати минут (по любым причинам, включая исчезновение энергопитания, наводнения и землетрясения). Мы не будем углубляться в детали — легче научить новичка, не знающего физики, вычислить поправки к курсу космического аппарата, спускающегося на поверхность Марса, — но попытаемся изложить идеи, которые могут оказаться полезными при тестировании менее крупных проектов или для понимания принципов тестирования более крупных систем.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Прежде всего следует вспомнить, что целью тестирования является поиск ошибок, особенно часто встречающихся и потенциально опасных. Написать и выполнить большое количество тестов не просто. Отсюда следует, что для тестировщика крайне желательно понимать сущность тестируемой системы. Для эффективного тестирования систем знание прикладной области еще важнее, чем для тестирования отдельных модулей. Для разработки системы необходимо знать не только язык программирования и компьютерные науки, но и прикладную область, а также людей, которые будут использовать приложение. Это является одной из мотиваций для работы с программами: вы увидите много интересных приложений и встретите много интересных людей.

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