#import "@docs/bmstu:1.0.0":*
#import "@preview/tablex:0.0.8": tablex, rowspanx, colspanx, cellx
#show: student_work.with(
  caf_name: "Компьютерные системы и сети",
  faculty_name: "Информатика и системы управления",
  work_type: "лабораторной работе",
  work_num: "2",
  discipline_name: "Технология разработки программных систем",
  theme: "Тестирование программного обеспечения (Вариант 11)",
  author: (group: "ИУ6-42Б", nwa: "<NAME>"),
  adviser: (nwa: "<NAME>"),
  city: "Москва",
  table_of_contents: true,
)

= Ручное тестирование программных продуктов

== Задание

Программа должна формировать типизированный файл с информацией о фамилии человека, дне рождения, а также осуществлять поиск в файле информации о дне рождения (файл исходного кода v11.doc).

== Методы ручного тестирования

Основными методами ручного тестирования являются:
- инспекции исходного текста;
- сквозные просмотры;
- просмотры за столом;
- обзоры программ.

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

Для тестирования методом сквозным просмотров требуется группа из 3-5 человек: председатель или координатор, секретарь, фиксирующий все ошибки, специалист по тестированию, программист и независимый эксперт. Поэтотму данный метод тестирования тоже не возможен в рамках выполнения лабораторной работы.

В методе оценки посредством просмотра выбирается программист, который должен выполнять обязанности администратора процесса. Администратор набирает группу от 6 до 20 участников, которые должны быть одного профиля. Каждому участнику предлагается представить для рассмотрения две программы: наилучшую и наихудшую. Отобранные программы случайным образом распределяются между участниками. Им дается по 4 программы — две наилучшие и две наихудшие, но программист не знает, какая из них плохая, а какая хорошая. Программист просматривает их и заполняет анкету, в которой предлагается оценить их относительное качество по шкале из семи баллов. Кроме того, проверяющий дает общий комментарий и рекомендации по улучшению программы. Так как в данной лабораторной требуется оценить только одну программу данный метод тоже не подходит.

== Метод проверки за столом

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

- полностью неупорядоченный процесс проверки;
- отсутствие обмена мнениями и здоровой конкуренции;
- меньшая эффективность по сравнению с другими методами.

Несмотря на недостатки, данный метод является единственным возможным в рамках выполнения лабораторной работы.

Приведем список вопросов, на которые будем ссылаться позже, в таблице тестирования.

1. Обращения к данным.
  1. Все ли переменные инициализированы?
  2. Не превышены ли максимальные (или реальные) размеры массивов и строк?
  3. Не перепутаны ли строки со столбцами при работе с матрицами?
  4. Присутствуют ли переменные со сходными именами?
  5. Используются ли файлы? Если да, то
    1. при вводе из файла проверяется ли завершение файла?
    2. соответствуют ли типы записываемых и читаемых значений?
  6. Использованы ли нетипизированные переменные, открытые массивы, динамическая память? Если да, то
    1. соответствуют ли типы переменных при наложении формата?
    2. не выходят ли индексы за границы массивов?
2. Вычисления.
  1. Правильно ли записаны выражения (порядок следования операторов)?
  2. Корректно ли производятся вычисления неарифметических переменных?
  3. Корректно ли выполнены вычисления с переменными различных типов (в том числе с использованием целочисленной арифметики)?
  4. Возможны ли переполнение разрядной сетки или ситуация машинного нуля?
  5. Соответствуют ли вычисления заданным требованиям точности?
  6. Присутствуют ли сравнения переменных различных типов?
3. Передачи управления.
  1. Будут ли корректно завершены циклы?
  2. Будет ли завершена программа?
  3. Существуют ли циклы, которые не будут выполняться из-за нарушения условия входа? Корректно ли продолжатся вычисления?
  4. Существуют ли поисковые циклы? Корректно ли отрабатываются ситуации «элемент найден» и «элемент не найден»?
4. Интерфейс.
  1. Соответствуют ли списки параметров и аргументов по порядку, типу, единицам измерения?
  2. Не изменяет ли подпрограмма аргументов, которые не должны изменяться?
  3. Не происходит ли нарушения области действия глобальных и локальных переменных с одинаковыми именами?

Далее приведем код непосредственно тестируемой программы.

#let lab2_1 = read("1.cpp")
#code(lab2_1, "cpp", [Код, предоставленный для ручного тестирования], num:true, size:12.2pt)

Заполним таблицу тестирования данными.
#align(center)[
  #tablex(
    columns: 4,
    inset: 10pt,
    align: horizon+center,
    [Номер\ вопроса],[Строки,\ подлежащие\ проверке],[Результат проверки],[Вывод],
    
    [1.1],[15-19,\ 21, 25,\ 32, 34],
    [Переменные, используемые в программе:\ ```c f, fb, key, fff```\ 
    Переменные, инициализированные в программе:\ ```c f, fb, n, key, fff```],
    [Все используемые переменные инициализированы],

    [1.2],[25, 32],
    [Строки в программе:\ ```c fb.ff, fff```],
    [Используются динамические строки типа ```cpp std::string```, размеры не могут быть превышены],
    
    [1.3],[],
    [Работа с матрицами не производится],
    [],

    [*1.4*],[25, 32],
    [Переменные, инициализированные в программе:\ ```c f, fb, n, key, fff```],
    [_Переменные со схожими именами присутствуют:\ ```c f, fb, fff, fb.ff```_],
    
    [*1.5.1*],[37],
    [Проверка присутствует, выполнена с помощью сравнения количества данных, прочтенных успешно, с 20\ Проверки об успешном открытии файла отсутствуют],
    [_Проверка на завершение при чтении построена некорректно, так как читается всегда только один набор данных_],
    
    [*1.5.2*],[21, 26,\ 35, 37],
    [Файл открыт в режиме `r` и `w`\ Записываемый тип: ```cpp fam```\ Читаемый тип: ```cpp fam```],
    [_Режимы не соответствует условию о типизированных данных. Необходимо открывать файл в бинарных режимах `rb` и `wb`._\ Типы соответствуют],

    [1.6],[],
    [Память выделяется динамически только в библеотеках],[],

    [2],[],
    [Вычисления\ в программе\ не производятся],[],

    [*3.1*],[24, 37],
    [Условием завершения первого цикла, вероятнее всего был выбран конец ввода\ Условием завершения 2 цикла, вероятнее всего, был выбран конец файла],[_Оба условия написаны неверно: для конца ввода необходимо проверять не конец файла, а непосредственно возращаемое значение ```cpp cin```, для конца файла можно проверять считываемые значения, но учесть, что всегда считывается одно значение, а не 20_],

    [*3.2*],[48-49],
    [Программа заканчивается закрытием читаемого файла],[_Код выхода из программы не возвращен, что может привести к непредвиденным ошибкам после выполнения программы_],

    [3.3],[24, 37],
    [Условиями входа обоих циклов являются открытый на запись и чтение файл],[Входы в циклы будут производиться верно],

    [3.4],[37-46],
    [Поисковый цикл организован структурно: объявлен флаг выхода если найдено, в услоии прописан флаг, после цикла обработка если ничего так и не было найдено],[Поисковый алгоритм цикла организован верно],

    [*4.1*],[21, 22,\ 25, 26,\ 29, 31,\ 32, 35,\ 37, 39-40,\ 46, 48],
    [Список параметров и аргументов по порядку, типу, единицам измерения соответствует с ожидаемыми параметрами и аргументами библеотечными функциями. Выбор типа ```cpp unsigned char``` неуместен для месяца и даты, так как преобразование в ```cpp short``` может выполняться некорректно для некоторых версий языка],[_Необходимо изменить тип ```cpp unsigned char``` на другой, к примеру ```cpp short```_],

    [4.2],[6-49],
    [Структура изменения переменных в программе соответствует условию задачи],[Программа не изменяет аргументы, которые не должны изменяться],

    [4.3],[],
    [Глобальные переменные в коде отсутствуют],[],
  )
]
== Заключение
При ручном тестировании получили ошибки в 6 пунктах: 1.4, 1.5.1, 1.5.2, 3.1, 3.2, 4.1.

Исправим найденные ошибки и перепишем код:

#let lab2_1n = read("1n.cpp")
#code(lab2_1n, "cpp", [Исправленный, после ручного тестирования, код], num:true, size:8.7pt)

= Белый ящик
== Задание


Дана схема алгоритма:

#img(image("1.png", width: 80%), [Схема алгоритма])

По схеме алгоритма видим, что на вход программы поступают некоторые данные: `a`, `b`, `x`.

== Покрытие операторов

Критерий покрытия операторов подразумевает выполнение каждого оператора программы по крайней мере 1 раз. Это необходимое, но недостаточное условие для приемлемого тестирования.

Сделаем таблицу, в которой подберем несколько разных наборов данных, чтобы покрыть все операторы:

#align(center)[
  #tablex(
    columns: 6,
    inset: 10pt,
    align: horizon+center,
    colspanx(3)[Входные данные], rowspanx(2)[Оператор], rowspanx(2)[Z], rowspanx(2)[Программный\ результат],
    [a], [b], [x],
    [1], [$forall$], [1], $ Z = sum_(k = 0)^infinity 1/(x^k times a^k) $, $infinity$, [$infinity$ (число k, до которого программа будет обрабатывать цикл)],
    [0.1], [$forall$], [1], $ Z = sum_(k = 0)^infinity x^k times a^(2 k) $, [$100/99$], [$1.010101010$],
    [0.1], [$forall$], [0.1], [$ Z = sum_(k = 0)^infinity x^k / a^k $], $infinity$, [$infinity$ (число k, до которого программа будет обрабатывать цикл)],
    [0], [0.1], [1], $ Z = sum_(k = 0)^infinity x^k times b^(2 k) $, [$100/99$], [$1.010101010$],
    [0], [1], [1], [$ Z = sum_(k = 0)^infinity -x^k / b^(2k) $], $-infinity$, [$-infinity$ (обратное числу k, до которого программа будет обрабатывать цикл)],
  )
]

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

== Покрытие решений

Для реализации этого критерия необходимо достаточное количество тестов, такое, что каждое решение на этих тестах принимает значение «истина» или «ложь» по крайней мере 1 раз

Так как все операторы стоят после условных переходов (т. е. за 1 проход можно попасть только в один из операторов), то при покрытия решений количество тестов, сделанное для покрытия операторов не изменится (так как за один путь мы не можем покрыть 2 оператора). 

#align(center)[
  #tablex(
    columns: 6,
    inset: 10pt,
    align: horizon+center,
    colspanx(3)[Входные данные], rowspanx(2)[Назначение\ теста], rowspanx(2)[Z], rowspanx(2)[Программный\ результат],
    [a], [b], [x],
    [1], [$forall$], [1], [Нет Нет Нет], $infinity$, [$infinity$ (число k, до которого программа будет обрабатывать цикл)],
    // [0.1], [$forall$], [1], [Нет Нет Да], [$100/99$], [$1.010101010$],
    // [0.1], [$forall$], [0.1], [Нет Да], $infinity$, [$infinity$ (число k, до которого программа будет обрабатывать цикл)],
    [0], [0.1], [1], [Да Нет Да], [$100/99$], [$1.010101010$],
    // [0], [1], [1], [Да Нет Нет], $-infinity$, [$-infinity$ (обратное числу k, до которого программа будет обрабатывать цикл)],
    // [0], [0], [$forall$], [Да Да], [Введенные\ данные], [Введенные\ данные],
  )
] 

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

== Покрытие решений/условий

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

#align(center)[
  #tablex(
    columns: 7,
    inset: 10pt,
    align: horizon+center,
    rowspanx(2)[№],colspanx(3)[Входные данные], rowspanx(2)[Назначение\ теста], rowspanx(2)[Z], rowspanx(2)[Программный\ результат],
    [a], [b], [x],
    [1],[1], [$forall$], [1], [Нет Нет Нет], $infinity$, [$infinity$ (число k, до которого программа будет обрабатывать цикл)],
    [2],[0.1], [$forall$], [1], [Нет Нет Да], [$100/99$], [$1.010101010$],
    [3],[0.1], [$forall$], [0.1], [Нет Да], $infinity$, [$infinity$ (число k, до которого программа будет обрабатывать цикл)],
    [4],[0], [0.1], [1], [Да Нет Да], [$100/99$], [$1.010101010$],
    [5],[0], [1], [1], [Да Нет Нет], $-infinity$, [$-infinity$ (обратное числу k, до которого программа будет обрабатывать цикл)],
    [6],[0], [0], [$forall$], [Да Да], [Введенные\ данные], [Введенные\ данные],
  )
] 

Недостатки метода:
- не всегда можно проверить все условия;
- невозможно проверить условия, которые скрыты другими условиями;
- недостаточная чувствительность к ошибкам в логических выражениях

== Комбинаторное покрытие условий

Данный критерий требует создания такого числа тестов, чтобы все возможные комбинации результатов условий в каждом решении и все точки входа выполнялись по крайней мере 1 раз.

Каждая из 3 входных переменных может быть нулем, по модулю меньше 1 (и не ноль) и по модулю больше или равно 1. Обозначим эти состояния переменных цифрами: 0, 1 и 2. Так как у нас 3 переменные, у каждой из которых может быть 3 состояния, то по комбинаторной формуле получаем всего $3*3*3 = 27$ состояний. Предыдущая таблица была с хорошо проработанными тестами, так что покажем, что все тесты из прошлой таблицы покрывают эти 27 состояний. Получим таблицу:

#align(center)[
  #tablex(
    columns: 4,
    inset: 10pt,
    align: horizon+center,
    rowspanx(2)[Номер теста], colspanx(3)[Входные\ данные], 
    [a], [b], [x],
    // [$eq.not 0$], [$forall$], [$> -1; < 1$],
    rowspanx(12)[1],
    $1$,$0$,$1$,
    $1$,$1$,$1$,
    $1$,$2$,$1$,
    $2$,$0$,$1$,
    $2$,$1$,$1$,
    $2$,$2$,$1$,
    $1$,$0$,$0$,
    $1$,$1$,$0$,
    $1$,$2$,$0$,
    $2$,$0$,$0$,
    $2$,$1$,$0$,
    $2$,$2$,$0$,
    // [$eq.not 0; > -1; < 1$], [$forall$], [$<= -1; >= 1$], 
    rowspanx(3)[2],
    $1$,$0$,$2$,
    $1$,$1$,$2$,
    $1$,$2$,$2$,
    // [$eq.not 0; <= -1; >= 1$], [$forall$], [$<= -1; >= 1$], 
    rowspanx(3)[3],
    $2$,$0$,$2$,
    $2$,$1$,$2$,
    $2$,$2$,$2$,
    // [$= 0$], [$= 0$], [$forall$], 
    rowspanx(3)[4],
    $0$,$0$,$0$,
    $0$,$0$,$1$,
    $0$,$0$,$2$,
    // [$= 0$], [$eq.not 0; > -1; < 1$], [$forall$], 
    rowspanx(3)[5],
    $0$,$1$,$0$,
    $0$,$1$,$1$,
    $0$,$1$,$2$,
    // [$= 0$], [$eq.not 0; <= -1; >= 1$], [$forall$], 
    rowspanx(3)[6],
    $0$,$2$,$0$,
    $0$,$2$,$1$,
    $0$,$2$,$2$,
  )
] 

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

== Заключение

В ходе тестирования было найдено 6 тестов, способных покрыть любые ошибки алгоритма. Арифметических ошибок не было найдено.

= Черный ящик

Одним из способов проверки программ является стратегия тестирования, называемая стратегией «черного ящика» или тестированием с управлением по данным. В этом случае программа рассматривается как «черный ящик» и цель такого тестирования — выяснение обстоятельств, в которых поведение программы не соответствует спецификации. Для обнаружения всех ошибок в программе необходимо выполнить исчерпывающее тестирование, т. е. тестирование на всех возможных наборах данных. Для тех программ, где исполнение команды зависит от предшествующих ей событий, необходимо проверить и все возможные последовательности. Очевидно, что построение исчерпывающего входного теста для большинства случаев невозможно. Поэтому обычно выполняется разумное тестирование, при котором тестирование программы ограничивается прогонами
на небольшом подмножестве всех возможных входных данных. Естественно при этом целесообразно выбрать наиболее подходящее подмножество (подмножество с наивысшей вероятностью обнаружения ошибок).

Правильно выбранный тест подмножества должен обладать следующими свойствами:
+ уменьшать, причем более чем на единицу, число других тестов, которые должны быть разработаны для достижения заранее определенной цели «приемлемого» тестирования;
+ покрывать значительную часть других возможных тестов, что в некоторой степени свидетельствует о наличии или отсутствии ошибок до и после применения этого ограниченного множества значений входных данных.
Стратегия «черного ящика» включает в себя следующие методы формирования тестовых наборов:
- эквивалентное разбиение;
- анализ граничных значений;
- анализ причинно-следственных связей;
- предположение об ошибке.

== Задание

Программа должна строить график функции по заданным в таблице значениям. Обеспечить возможность выбора вида графика: точки отдельно или точки соединены (исполняемый модуль v11.exe).

Интерфейс программы представлен ниже:

#img(image("2.png", width: 80%), [Поле для ввода данных])
#img(image("3.png", width: 80%), [Результат работы программы])


== Метод эквивалентного разбиения

Основу метода составляют два положения:
+ Исходные данные программы необходимо разбить на конечное число классов эквивалентности, так чтобы можно было предположить, что каждый тест, являющийся представителем некоторого класса, эквивалентен любому другому тесту этого класса. Иными словами, если тест какого-либо класса обнаруживает ошибку, то предполагается, что все другие тесты этого класса эквивалентности тоже обнаружат эту ошибку, и наоборот;
+ Каждый тест должен включать по возможности максимальное количество различных входных условий, что позволяет минимизировать общее число необходимых тестов.

Первое положение используется для разработки набора «интересных» условий, которые должны быть протестированы, а второе — для разработки минимального набора тестов. Разработка тестов методом эквивалентного разбиения осуществляется в два этапа: выделение классов эквивалентности и построение тестов.

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

То есть максимум для проверки понадобится 2 точки, если программа будет работать для 2 точек, то для большего количества точек она тоже будет работать.

Выделим 5 входных условий:
- Ввод координаты по X точки 1
- Ввод координаты по Y точки 1
- Ввод координаты по X точки 2
- Ввод координаты по Y точки 2
- Отметка соединить точки 

#align(center)[
  #tablex(
    columns: 3,
    inset: 10pt,
    align: horizon+center,
    [Входное условие],[Правильные классы эквивалентности],[Неправильные классы эквивалентности],
    [Ввод координаты по X точки 1],[Целое, вещественное],[],
    [Ввод координаты по Y точки 1],[],[],
    [Ввод координаты по X точки 2],[],[],
    [Ввод координаты по Y точки 2],[],[],
    [Отметка соединить точки],[```cpp true, false```],[--]
)]

Так как не на какие координаты не накладываются ограничения по заданию неправильных классов эквивалентности нет.
#pagebreak()
Составим тесты (тут сразу виден недочет программы: нельзя задать произвольное количество точек, поэтому во время тестирования точки, не участвующие в тестировании будут иметь значения по умолчанию):

#align(center)[
  #tablex(
    columns: 6,
    inset: 10pt,
    align: horizon+center,
    $x_1$, $y_1$, $x_2$, $y_2$, [Соединить\ точки], [Результат], 
    [1], [1], [2], [2], [true],[График построен верно],
    [1], [1], [2], [2], [false],[График построен верно],
    [2], [2], [1], [1], [true],[Ошибка: точка с меньшими координатами не определяется в графике после точки с большими],
    [2], [0], [1], [1], [true],[Ошибка: точка с меньшей координатой не определяется в графике после точки с большей],
    [0], [2], [1], [1], [true],[Ошибка: точка с меньшей координатой не определяется в графике после точки с большей],
    [1], [1], [1], [1], [true],[Ошибка: точка с одинаковыми координатами не определяется в графике после первой точки],
    [0], [1], [1], [1], [true],[Ошибка: точка с одинаковой координатой не определяется в графике после первой точки],
    [1], [0], [1], [1], [true],[Ошибка: точка с одинаковой координатой не определяется в графике после первой точки],
    [-1], [1], [2], [2], [true],[График построен верно],
    [1], [-1], [2], [2], [true],[График построен верно],
    [-1], [-1], [2], [2], [true],[График построен верно],
)]

С помощью тестирования удалось определить 2 ошибки: при вводе точки с меньшими или равными координатами по любой из осей программа перестает работать, второй ошибкой является отсутствие возможности задать другое количество точек. Данную возможность можно было бы легко добавить, обрабатывая пустые строки отдельно. Так же в процессе тестирования выявлено, что в программе предусмотрено различное кол-во точек: это следует из ошибки о введенной только одной точки, когда программа перестает видеть вторую точку из-за первой ошибки.


== Анализ граничных значений 

Граничные условия — это ситуации, возникающие вблизи и на границах входных классов эквивалентности.

Анализ граничных значений отличается от эквивалентного разбиения следующим:
- выбор любого элемента в классе эквивалентности в качестве представительного при анализе граничных условий осуществляется таким образом, чтобы проверить тестом каждую границу этого класса;
- при разработке тестов рассматриваются не только входные условия (пространство входов), но и пространство результатов.

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

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


По условию граничные значения не заданы, поэтому будем проверять все возможные варианты.

После проверки чисел $10^10$, $10^100$, $10^200$, $10^300$, $10^400$, $10^310$, $10^309$, $10^308$,$10^307$ было выявлено, что на отрезке от $10^307$ до $10^308$ программа ломается и все последующие числа программа просто выдает как что-то, меньшее бесконечности. Так как числа представляются в памяти в двоичном виде логично предположить, что программа ломается как раз на большой степени двойки, $10^308 tilde.eq 2^1024$. Таким образом можно предположить, что в программе используется динамическая типизация, но с ограничением на выделение памяти до 256 (128 байт = 1024 бит и отриц. числа) байт (или для каждой координаты изначально выделяется 256 байт статически). Поведение программы является неправильным только при очень больших числах, поэтому данные ограничения можно считать приемлемыми.
#pagebreak()

== Анализ причинно-следственных связей
#align(center)[
  #tablex(
    columns: 5,
    inset: 5pt,
    align: horizon+center,
    [Назначение теста],[Значения исходных данных],[Ожидаемый результат],[Реакция программы],[Вывод],
    [Выделение содержимого ячейки для исправления/удаления], [Тройной клик\ по ячейке],colspanx(2)[Выделение содержимого], [Программа работает верно], 
    [Прокручивание горизонтального ползунка],[Прокручивание горизонтального ползунка],colspanx(2)[Прокрутка страницы], [Программа работает верно], 
    [Блокировка вертикального ползунка],[Прокручивание вертикального ползунка],[Блокировка действия: пользователю доступны все строки таблицы без прокрутки],[Прокрутка таблицы вниз], [*Программа работает не верно*], 
    [Проверка ввода после выделения],[Ввод знака и цифр с клавиатуры],[Отображение введенного числа в ячейке полностью],[Число отображается в ячейке, но не полностью. Доступна прокрутка внутри ячейки], [_Программа работает не совсем верно_], 
    [Проверка работы checkbox'а для соединения точек],[Нажатие на checkbox],colspanx(2)[Изменение значения на\ противоположное], [Программа работает верно], 
    [Работоспособность кнопки\ Построить],[Нажатие на кнопку],colspanx(2)[Отображение графика], [_Программа работает не совсем верно (зависит от входных данных)_]
  )
]
== Предположение об ошибке

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

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

Так как программа должна строить график при любых двух и более заданных точках, то если эти 2 точки не заданы, необховыводить сообзение об ошибке, иначе просто строить график. Построим логическую схему, которая будет отражать всю работоспособность программы и проверку на то, что любые 2 точки заданы.

#img(image("4.png", width: 88%), [Логическая схема])


== Заключение
В результате исследования методов тестирования были получены следующие результаты:
- выявлены ошибки в алгоритме построения графика;
- выявлены ошибки в интерфейсе (причинно-следственной связи);
- выявлены ошибки в задании граничных значений;
- оценена специфика каждого метода тестирования;
- оценена трудоемкость тестирования для каждого метода.




