10.  Тестване и настройка

 
"Мисля, че е съществено програмите да се показват в окончателен
вид, като се обръща достатъчно внимание на подробностите,
защото в програмирането зад подробностите се крие
дяволът."
Никлаус Вирт
 
Самостоятелно тестване на функции.
** Данните, с които ще се тества функцията, се получават по 3 начина:
-- от входния поток;
-- като стойности, получени от цикъл;
-- случайни числа.
** Примери за тестване на функцията squareroot за намиране на квадратен корен по метода на Херон. Записваме текстовете на функциите squareroot и not_equal в отделен файл:
// sq_root.cpp
bool not_equal(double x, double y)
{
   const double EPSILON = 1E-14;
   double dmax = fabs(x);
   if (fabs(y) > dmax) dmax = fabs(y);
   return fabs(x - y) > dmax * EPSILON;
}
double squareroot(double a)
{  if (a == 0) return 0;
   double xnew = a;
   double xold;
   do
   {  xold = xnew;
      xnew = (xold + a / xold) / 2;
   }
   while (not_equal(xnew, xold));
   return xnew;
}
* Първи пример - данните идват от входния поток:
// sqrtest1.cpp
#include <iostream>
#include <cmath>
using namespace std;

#include "sq_root.cpp"
/* Тестващо гнездо */
int main()
{  double x;
   while (cin >> x)
   {  double y = squareroot(x);
      cout << "squareroot of " << x << " = " << y << "\n";
   }
   return 0;
}

25
squareroot of 25 = 5
3
squareroot of 3 = 1.73205
q

* Втори пример - входните стойности на функцията се генерират от цикъл.
// sqrtest2.cpp
#include <iostream>
#include <cmath>
using namespace std;

#include "sq_root.cpp"
/* Тестващо гнездо */
int main()
{  double x;
   for (x = 0; x <= 2; x += 0.5)
   {  double y = squareroot(x);
      cout << "squareroot of " << x << " = " << y << "\n";
   }
   return 0;
}

squareroot of 0 = 0
squareroot of 0.5 = 0.707107
squareroot of 1 = 1
squareroot of 1.5 = 1.22474
squareroot of 2 = 1.41421

* Трети пример - входните стойности се получават от генератор за случайни числа.
// sqrtest3.cpp
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <ctime>
using namespace std;

#include "sq_root.cpp"
void rand_seed()
{
   int seed = static_cast<int>(time(0));
   srand(seed);
}
double rand_double(double a, double b)
{  return a + (b - a) * rand()*(1.0/RAND_MAX);
}
/* Тестващо гнездо */
int main()
{  rand_seed();
   int i;
   for (i = 1; i <= 4; i++)
   {  double x = rand_double(0, 1E6);
      double y = squareroot(x);
      cout << "squareroot of " << x << " = " << y << "\n";
   }
   return 0;
}

squareroot of 185949 = 431.218
squareroot of 680715 = 825.055
squareroot of 17883.8 = 133.73
squareroot of 238868 = 488.742

Подбор на тестови примери.
1. Докато се пише програмата, трябва да имаме прост тестов пример, на който знаем решението.
2. Програмата се проверява с други тестови примери, също с известни решения - позитивни тестове.
3. Включват се и граничните случаи. Например за функцията squareroot това са 0, големи числа (напр. 1Е20) и числа, близки до 0 (напр.1е-20). Целта е да се определят границите на параметрите, за които функцията работи вярно.
4. Функцията се проверява с негативни тестови примери - некоректни входни данни. Такива за squareroot са отрицателни стойности на параметъра.



Оценка на резултатите от тестването.
** Как можем да оценим дали върнатата стойност от функцията е вярна:
- като предварително знаем решението;
- с програма за проверка на върнатите стойности;
- с "оракул" - друга функция, която решава същата задача (може по-бавно и неефективно!).
** В нашия случай можем да сравним квадрата на върнатото число от функцията с входната стойност. Ето тестващото гнездо:
int main()
{  int i;
   for (i = 1; i <= 100; i++)
   {  double x = rand_double(0, 1E6);
      double y = squareroot(x);
      if (not_equal(y * y, x))  cout << "Test failed. ";
      else                      cout << "Test passed. ";
      cout << "squareroot of " << x << " = " << y << "\n";
   }
   return 0;
}
**  За оракул можем да използваме стандартната аритметична функция pow(x,0.5)или функцията sqrt(x).
/* Тестващо гнездо */
int main()
{
   rand_seed();
   int i;
   for (i = 1; i <= 100; i++)
   {  double x = rand_double(0, 1E6);
      double y = squareroot(x);
      if (not_equal(y, pow(x, 0.5))) cout << "Test failed. ";
      else                           cout << "Test passed. ";
      cout << "squareroot of " << x << " = " << y << "\n";
   }
   return 0;
}