Литмир - Электронная Библиотека
A
A
Программирование. Принципы и практика использования C++ Исправленное издание - _334.png

 

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

26.3.5. Тестирование классов

С формальной точки зрения тестирование классов представляет собой тестирование модулей, но с учетом того, что у каждого класса обычно есть несколько функций-членов и некоторое состояние, тестирование классов имеет признаки тестирования систем. Особенно это относится к базовым классам, которые необходимо рассматривать в разных контекстах (определенных разными производными классами). Рассмотрим класс

Shape
из раздела 14.2.

class Shape { // задает цвет и стиль, хранит последовательность линий

public:

  void draw() const;                 // задает цвет и рисует линии

  virtual void move(int dx, int dy); // перемещает фигуру

                                     // на +=dx и +=dy

  void set_color(Color col);

  Color color() const;

  void set_style(Line_style sty);

  Line_style style() const;

  void set_fill_color(Color col);

  Color fill_color() const;

  Point point(int i) const; // доступ к точкам без права

                            // модификации

  int number_of_points() const;

  virtual ~Shape() { }

protected:

  Shape();

  virtual void draw_lines() const; // рисует соответствующие точки

  void add(Point p);               // добавляет точку p

  void set_point(int i,Point p);   // points[i]=p;

private:

  vector<Point> points; // не используется всеми

  // фигурами

  Color lcolor;         // цвет для линий и символов

  Line_style ls;

  Color fcolor;         // цвет заполнения

  Shape(const Shape&);  // предотвращает копирование

  Shape& operator=(const Shape&);

};

Как приступить к тестированию этого класса? Сначала рассмотрим, чем класс

Shape
отличается от функции
binary_search
с точки зрения тестирования.

• Класс

Shape
имеет несколько функций.

• Состояние объекта класса

Shape
может изменяться (мы можем добавлять точки, изменять цвет и т.д.), т.е. одна функция может влиять на другую.

• Класс

Shape
имеет виртуальные функции. Другими словами, поведение объекта класса
Shape
зависит от того, какой производный класс был создан на его основе (если такой класс существует).

• Класс

Shape
не является алгоритмом.

• Изменение объекта класса

Shape
может влиять на содержимое экрана.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Последний момент особенно неприятный. По существу, это значит, что мы должны посадить перед компьютером человека, который будет смотреть, правильно ли ведет себя объект класса
Shape
. Это не соответствует принципам систематичного, воспроизводимого и доступного тестирования. Как указывалось в разделе 26.3.4.1, мы часто прибегаем к разным уловкам, чтобы избежать этого. Однако пока будем предполагать, что существует наблюдатель, который замечает отклонения изображения от требуемого образца.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Отметим важную деталь: пользователь может добавлять точки, но не может их удалять. Пользователь или функции класса
Shape
могут считывать точки, но не могут их изменять. С точки зрения тестирования все, что не вносит изменений (или, по крайней мере, не должно вносить), облегчает работу.

Что мы можем тестировать, а что не можем? Для того чтобы тестировать класс

Shape
, мы должны попытаться протестировать его как отдельно, так и в сочетании с производными классами. Однако, для того чтобы проверить, что класс
Shape
работает правильно с конкретным производным классом, мы должны протестировать этот производный класс.

Ранее мы уже отметили, что объект класса

Shape
имеет состояние (значение), определенное четырьмя данными-членами.

vector<Point> points;

Color lcolor; // цвет линий и символов

Line_style ls;

Color fcolor; // цвет заполнения

Все, что мы можем сделать с объектом класса

Shape
, — внести в него изменения и посмотреть, что произойдет. К счастью, изменить данные-члены можно только с помощью интерфейса, определенного функциями-членами.

Простейшим объектом класса

Shape
является объект класса
Line
, поэтому начнем с создания одного такого объекта и внесем все возможные изменения (используя самый наивный стиль тестирования).

Line ln(Point(10,10), Point(100, 100));

ln.draw();  // смотрим, что произошло

// проверка точек:

if (ln.number_of_points() != 2)

  cerr << "Неправильное количество точек ";

if (ln.point(0)!=Point(10,10)) cerr << "Неправильная точка 1";

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