\documentclass[a4paper, final]{article}
%\usepackage{literat} % Нормальные шрифты
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
\usepackage{tabularx}
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\usepackage{amsmath}
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
\usepackage{ragged2e} %для растягивания по ширине
\usepackage{setspace} %для межстрочно   го интервала
\usepackage{moreverb} %для работы с листингами
\usepackage{indentfirst} % для абзацного отступа
\usepackage{moreverb} %для печати в листинге исходного кода программ
\usepackage{pdfpages} %для вставки других pdf файлов
\usepackage{tikz}
\usepackage{graphicx}
\usepackage{afterpage}
\usepackage{longtable}
\usepackage{float}



% \usepackage[paper=A4,DIV=12]{typearea}
\usepackage{pdflscape}
% \usepackage{lscape}

\usepackage{array}
\usepackage{multirow}

\renewcommand\verbatimtabsize{4\relax}
\renewcommand\listingoffset{0.2em} %отступ от номеров строк в листинге
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
\usepackage[font=small, singlelinecheck=false, justification=centering, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
\usepackage{listings} %листинги
\usepackage{xcolor} % цвета
\usepackage{hyperref}% для гиперссылок
\usepackage{enumitem} %для перечислений

\newcommand{\specialcell}[2][l]{\begin{tabular}[#1]{@{}l@{}}#2\end{tabular}}


\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях

\hypersetup{colorlinks,
    allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)

% подгружаемые языки — подробнее в документации listings (это всё для листингов)
\lstloadlanguages{ Java}
% включаем кириллицу и добавляем кое−какие опции
\lstset{tabsize=2,
    breaklines,
    basicstyle=\footnotesize,
    columns=fullflexible,
    flexiblecolumns,
    numbers=left,
    numberstyle={\footnotesize},
    keywordstyle=\color{blue},
    inputencoding=cp1251,
    extendedchars=true
}
\lstdefinelanguage{MyC}{
    language=Java,
%    ndkeywordstyle=\color{darkgray}\bfseries,
%    identifierstyle=\color{black},
%    morecomment=[n]{/**}{*/},
%    commentstyle=\color{blue}\ttfamily,
%    stringstyle=\color{red}\ttfamily,
%    morestring=[b]",
%    showstringspaces=false,
%    morecomment=[l][\color{gray}]{//},
    keepspaces=true,
    escapechar=\%,
    texcl=true
}

\textheight=24cm % высота текста
\textwidth=16cm % ширина текста
\oddsidemargin=0pt % отступ от левого края
\topmargin=-1.5cm % отступ от верхнего края
\parindent=24pt % абзацный отступ
\parskip=5pt % интервал между абзацами
\tolerance=2000 % терпимость к "жидким" строкам
\flushbottom % выравнивание высоты страниц


% Настройка листингов
\lstset{
    language=Java,
    extendedchars=\true,
    inputencoding=utf8,
    keepspaces=true,
    % captionpos=b, % подписи листингов снизу
}

\begin{document} % начало документа
    


    % НАЧАЛО ТИТУЛЬНОГО ЛИСТА
    \begin{center}
        \hfill \break
        \hfill \break
        \normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ\\
            федеральное государственное автономное образовательное учреждение высшего образования «Санкт-Петербургский политехнический университет Петра Великого»\\[10pt]}
        \normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt] 
        \normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt] 
        \normalsize{Направление: 02.03.01 <<Математика и компьютерные науки>>}\\
        
        \hfill \break
        \hfill \break
        \hfill \break
        \hfill \break
        \large{Лабораторная работа №4}\\
        \large{<<Автоматизированное тестирование>>}\\
        \large{по дисциплине}\\
        \large{<<Методы тестирования программного обеспечения>>}\\
        \hfill \break
        
        % \hfill \break
        \hfill \break
    \end{center}
    
    \small{ 
        \begin{tabular}{lrrl}
            \!\!\!Студент, & \hspace{2cm} & & \\
            \!\!\!группы 5130201/20102 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
            \!\!\!Преподаватель & \hspace{2cm} &  \underline{\hspace{3cm}} &  Курочкин М. А. \\\\
            &&\hspace{4cm}
        \end{tabular}
        \begin{flushright}
            <<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2025г.
        \end{flushright}
    }
    
    \hfill \break
    % \hfill \break
    \begin{center} \small{Санкт-Петербург, 2025} \end{center}
    \thispagestyle{empty} % выключаем отображение номера для этой страницы
    
    % КОНЕЦ ТИТУЛЬНОГО ЛИСТА
    \newpage
    
    \tableofcontents


    \newpage
    
    \section{Постановка задачи}

    Данная лабораторная работа делится на две части. В первой части необходимо разработать набор юнит-тестов к предоставленной библиотеке calculator.jar, которая содержит методы для проведения разнообразных операций над числами. Во второй части необходимо протестировать сайт в Chrome путем написания двух тестов, проверяющих корректность отображения страниц. Использовать для тестирования Selenuim WebDriver.


    \newpage
    \section {Средства автоматизации тестирования}
    \subsection{JUinit}
    \textit{JUnit} — это фреймворк, созданный для тестирования программного обеспечения на языке Java. Он предназначен для разработки и выполнения автоматизированных тестов, что дает разработчикам возможность проверять правильность функционирования своего кода и обнаруживать ошибки на ранних стадиях разработки.

    
    \subsubsection{Основные особенности JUnit}
    \begin{itemize}
    \item\textbf{ Модульное тестирование:} JUnit поддерживает тестирование отдельных модулей, позволяя разработчикам проверять работу отдельных компонентов (методов и классов) независимо друг от друга.
    \item\textbf{ Аннотации:} JUnit использует аннотации, такие как \texttt{@Test}, \texttt{@Before}, \texttt{@After}, которые упрощают написание тестов и делают код более читабельным. Например, аннотация \texttt{@Before }позволяет выполнять определенный код перед каждым тестом, а @After — после его завершения.
    \item \textbf{Ассерты: }JUnit предоставляет различные методы ассертов, такие как assertEquals, assertTrue, assertNotNull, которые помогают проверять ожидаемые результаты тестов.
    \item \textbf{Группировка тестов:} Тесты могут быть сгруппированы с помощью аннотации @Suite, что позволяет запускать их вместе.
\item \textbf{    Интеграция:} JUnit просто интегрируется с различными инструментами и фреймворками, такими как Maven, Gradle и широко используемые IDE, включая Eclipse и IntelliJ IDEA, что упрощает процесс тестирования.

    \end{itemize}
\subsubsection{    Преимущества использования JUnit}
\begin{itemize}
    \item \textbf{Упрощение процесса тестирования:} JUnit делает написание тестов более удобным и структурированным.
    \item \textbf{Автоматизация:} Позволяет автоматизировать тесты, что снижает вероятность ошибок и повышает качество кода.\par 
    \item \textbf{Поддержка непрерывной интеграции:} JUnit хорошо совместим с системами непрерывной интеграции, позволяя запускать тесты автоматически при каждом изменении кода.
    \item \textbf{Снижение затрат на отладку:} Регулярное тестирование помогает выявлять проблемы на ранних стадиях, что уменьшает расходы на их исправление.
\end{itemize}
\subsubsection{Функционал библиотеки}
    JUnit имеет широкий функционал для проверки совпадения ожидаемого резульата, и результата полученного тестируемым методом.\par
    \vspace{5pt}
    Класс \texttt{junit.framework.Assert} предоставляет набор статических методов для проверки различных условий в тестах.
    
    \begin{itemize}
        \item \texttt{assertEquals(expected, actual)} - проверяет равенство двух значений. Если значения не равны, тест завершается с ошибкой. Имеет перегрузки для различных типов данных.
        
        \item \texttt{assertFalse(condition)} - проверяет, что переданное булево значение является \texttt{false}. Если значение \texttt{true}, тест завершается с ошибкой.
        
        \item \texttt{assertNotNull(object)} - проверяет, что объект не является \texttt{null}. Если объект \texttt{null}, тест завершается с ошибкой.
        
        \item \texttt{assertNull(object)} - проверяет, что объект является \texttt{null}. Если объект не \texttt{null}, тест завершается с ошибкой.
        
        \item \texttt{assertNotSame(unexpected, actual)} - проверяет, что два объекта не ссылаются на один и тот же экземпляр. Если ссылки идентичны, тест завершается с ошибкой.
        
        \item \texttt{assertSame(expected, actual)} - проверяет, что два объекта ссылаются на один и тот же экземпляр. Если ссылки разные, тест завершается с ошибкой.
        
        \item \texttt{assertTrue(condition)} - проверяет, что переданное булево значение является \texttt{true}. Если значение \texttt{false}, тест завершается с ошибкой.
    \end{itemize}
    
    Класс \texttt{junit.framework.TestCase} наследуется от \texttt{junit.framework.Assert} и предоставляет базовую функциональность для создания тестовых случаев.
    
    \begin{itemize}
        \item \texttt{run()} - основной метод, выполняющий тест. Содержит логику запуска и выполнения тестового случая.
        
        \item \texttt{setUp()} - метод, выполняемый перед каждым тестом. Используется для инициализации тестового окружения и подготовки данных. В аннотационной версии JUnit 4+ заменён на \texttt{@Before}.
        
        \item \texttt{tearDown()} - метод, выполняемый после каждого теста. Используется для очистки ресурсов после выполнения теста. В аннотационной версии JUnit 4+ заменён на \texttt{@After}.
    \end{itemize}
\subsubsection{Этапы написания тестов}
\begin{enumerate}
    \item \textbf{Реализация теста}: Написание тестового метода и аннотирование его с помощью. \texttt{@Test}
    \item \textbf{Настройка и очистка} Использование аннотаций \texttt{@Before} и \texttt{@After}
 для выполнения операйи перед и после теста.
     \item \textbf{Запуск тестов:} Использование встроенных средств IDE или командной строки для выполнения тестов.
\end{enumerate}
    \subsection{Selenium WebDriver}
    \textit{Selenium WebDriver } ---     это фреймворк с открытым исходным кодом для автоматизации тестирования веб-приложений. Он предоставляет программный интерфейс для взаимодействия с браузерами, позволяя эмулировать действия пользователя на веб-страницах.
    \textbf{Основные особенности Selenium WebDriver}:
    \begin{itemize}
    \item \textbf{Кроссбраузерность:} Поддержка всех популярных браузеров, включая Chrome, 
    Firefox, Safari, Edge и Opera.
    \item \textbf{Многоязычность:} Возможность написания тестовых скриптов на различных
    языках программирования — Java, Python, C\#, Ruby, JavaScript, PHP и Perl.
    \item \textbf{Прямое взаимодействие:} WebDriver напрямую отправляет команды браузеру и
    получает результаты, что обеспечивает более точное воспроизведение
    пользовательских действий.
    \item \textbf{Кроссплатформенность:} Возможность запуска тестов на различных операционных
    системах (Windows, MacOS, Linux).
    \item \textbf{Параллельное выполнение:} Поддержка одновременного запуска тестов в
    разных браузерах для ускорения тестирования.
\end{itemize}\par 
    
    Архитектура Selenium WebDriver состоит из четырех основных компонентов:
    \begin{itemize}
        \item     \textbf{Selenium Client Libraries:} Набор библиотек для различных языков 
    программирования, позволяющих писать и запускать тесты на предпочитаемом языке.
    JSON Wire Protocol: REST API на основе JSON, обеспечивающий передачу 
    информации между клиентом и сервером через HTTP.
    \item \textbf{Browser Drivers:} Специфичные для каждого браузера драйверы (ChromeDriver,
    GeckoDriver для Firefox и др.), которые получают команды и выполняют их
    в соответствующем браузере.
    \item \textbf{Browsers:} Сами браузеры, в которых выполняются тестовые сценарии.
        \end{itemize}
    \textbf{Этапы работы с WebDriver}:
    \begin{enumerate}
        \item  \textbf{Инициализация:} Создание экземпляра WebDriver и открытие браузера.
    \item \textbf{Навигация:} Переход к нужной веб-странице с помощью метода get().
    \item \textbf{Поиск элементов:} Обнаружение элементов на странице с использованием 
    различных локаторов (ID, XPath, CSS-селекторы и др.).
    \item \textbf{Взаимодействие:} Выполнение действий над элементами (клик, ввод текста,
    выбор из выпадающих списков и т.д.).
    \item \textbf{Ожидание:} Использование явных и неявных ожиданий для синхронизации 
    с динамическими элементами страницы.
    \item \textbf{Проверка:} Получение информации о состоянии элементов и проверка результатов.
    \item \textbf{Завершение:} Закрытие браузера и освобождение ресурсов.
        \end{enumerate}
    Принцип выполнения команд:
    \begin{enumerate}
        \item Команда из тестового скрипта преобразуется в HTTP-запрос через JSON Wire Protocol.
\item Запрос передается соответствующему драйверу браузера.
    \item Драйвер интерпретирует запрос и выполняет необходимые действия в браузере.
    \item Результат действия возвращается обратно в виде HTTP-ответа.
\item Ответ преобразуется в формат, понятный тестовому скрипту.
        \end{enumerate}


    \newpage
    \section{Описание выполненных работ}
    \subsection{Работа №1}
    В ходе работы необходимо прописать юнит тесты для методов библиотеки calcualtor.jar, реализующий функционал калькулятора, производящего вычисления суммы, разности, умножения, деления, возведения в степень, ивзлечение корня, а также значений базовых тригонометрических функций. Дря реализации тестов, необходимо использовать JUnit.
    
    \subsubsection{Класс CalculatorTest}
    Все тесты содержатся в классе CalculatorTest. В методе setUp() инициализируется объект \texttt{Calculator}. Константой DELTA задается допустимая погрешность. Код определения полей класса и метода setUp() представлен в листинге \ref{lst:CalculatorTest}.

    \begin{lstlisting}[caption={Класс CalculatorTest}, label={lst:CalculatorTest}]
    class CalculatorTest {
        private static final double DELTA = 0.0001;
        private Calculator calculator;
    
        @BeforeEach
        void setUp() {
            calculator = new Calculator();
        }
    }\end{lstlisting}
    
    \subsubsection{Тесты для метода Sum}
    В классе CalculatorTest реализованы следующие тесты для метода sum:

    \begin{itemize}
        \item \texttt{testLongSum} - тест для проверки суммы двух чисел типа long.
        \item \texttt{testDoubleSum} - тест для проверки суммы двух чисел типа double.
    \end{itemize}

    Код тестов представлен в листинге \ref{lst:SumTest}. Тесты параметризованы с помощью аннотации \texttt{@ParameterizedTest} и \texttt{@CsvSource}.

\begin{lstlisting}[caption={Тесты для метода Sum}, label={lst:SumTest}]
@ParameterizedTest
@CsvSource({
        "1, 2, 3",
        "5, 0, 5",
        "-7, 7, 0",
        "9223372036854775806, 1, 9223372036854775807"
})
void testLongSum(long a, long b, long expected) {
    assertEquals(expected, calculator.sum(a, b));
}

@ParameterizedTest
@CsvSource({
        "1.5, 2.5, 4.0",
        "5.5, 0.0, 5.5",
        "-3.5, 3.5, 0.0",
        "0.1, 0.2, 0.3"
})
void testDoubleSum(double a, double b, double expected) {
    assertEquals(expected, calculator.sum(a, b), DELTA);
}
\end{lstlisting}

    \textbf{Результаты запуска тестов:}

    Результаты запуска тестов представлены на рисунке \ref{fig:test1}.
    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.65\linewidth]{img/test1.png}
       \caption{Результаты запуска тестов для метода sum}
       \label{fig:test1}
    \end{figure}

    По итогам запуска, метод sum прошел все тесты.

    \subsubsection{Тесты для метода Mul}

    В классе CalculatorTest реализованы следующие тесты для метода mul:

    \begin{itemize}
        \item \texttt{testLongMul} - тест для проверки произведения двух чисел типа long.
        \item \texttt{testDoubleMul} - тест для проверки произведения двух чисел типа double.
    \end{itemize}

    Код тестов представлен в листинге \ref{lst:MulTest}.

\begin{lstlisting}[caption={Тесты для метода Mul}, label={lst:MulTest}]
@ParameterizedTest
@CsvSource({
        "2.5, 3.0, 7.5",
        "0.0, 5.5, 0.0",
        "-2.5, 3.0, -7.5",
        "-2.5, -3.0, 7.5"
})
void testDoubleMult(double a, double b, double expected) {
    assertEquals(expected, calculator.mult(a, b), DELTA);
}

@ParameterizedTest
@CsvSource({
        "2, 3, 6",
        "0, 5, 0",
        "-2, 3, -6",
        "-2, -3, 6",
        "1000, 1000, 1000000"
})
void testLongMult(long a, long b, long expected) {
    assertEquals(expected, calculator.mult(a, b));
}
\end{lstlisting}

    \textbf{Результаты запуска тестов:}

    Результаты запуска тестов представлены на рисунке \ref{fig:test2}.

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.65\linewidth]{img/test2.png}
       \caption{Результаты запуска тестов для метода mul}
       \label{fig:test2}
    \end{figure}

    По итогам запуска, метод mul для типа long прошел все тесты, а для типа double прошёл лишь 1 из 4 тестов. 

    \subsubsection{Тесты для метода Sqrt}

    В классе CalculatorTest реализованы следующие тесты для метода sqrt:

    \begin{itemize}
        \item \texttt{testSqrt} - тест для проверки квадратного корня числа типа double. Проверяет положительные, отрицательные значения, а также 0.
    \end{itemize}

    Код тестов представлен в листинге \ref{lst:SqrtTest}.

\begin{lstlisting}[caption={Тесты для метода Sqrt}, label={lst:SqrtTest}]
@ParameterizedTest
@ValueSource(doubles = { 4.0, 0.0, -4.0, 1000000.0 })
void testSqrt(double value) {
    double expected = Math.sqrt(value);
    assertEquals(expected, calculator.sqrt(value), DELTA);
}
\end{lstlisting}

    \textbf{Результаты запуска тестов:}

    Результаты запуска тестов представлены на рисунке \ref{fig:test3}.

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.55\linewidth]{img/test3.png}
       \caption{Результаты запуска тестов для метода sqrt}
       \label{fig:test3}
    \end{figure}
    
    По итогам запуска, метод sqrt не прошёл один из четырёх тестов. Метод неккоректно работает с отрицательными числами.

    \subsubsection{Тесты для метода Tg}

    В классе CalculatorTest реализованы следующие тесты для метода tg:

    \begin{itemize}
        \item \texttt{testTg} - тест для проверки тангенса числа типа double. Проверяет положительные, отрицательные значения, а также 0.
    \end{itemize}

    Код тестов представлен в листинге \ref{lst:TgTest}.

\begin{lstlisting}[caption={Тесты для метода Tg}, label={lst:TgTest}]
@ParameterizedTest
@ValueSource(doubles = { 0, Math.PI / 6, Math.PI / 4, -Math.PI / 3, 10 })
void testTg(double angle) {
    double expected = Math.tan(angle);
    double actual = calculator.tg(angle);
    assertEquals(expected, actual, 0.0001);
}
\end{lstlisting}

    \textbf{Результаты запуска тестов:}

    Результаты запуска тестов представлены на рисунке \ref{fig:test4}.

    \begin{figure}[h!]
       \centering
       \includegraphics[width=0.65\linewidth]{img/test4.png}
       \caption{Результаты запуска тестов для метода tg}
       \label{fig:test4}
    \end{figure}
    
    По итогам запуска, метод tg прошел лишь 1 из 5 тестов.

    \subsubsection{Результаты работы №1}
    В результате комплексного тестирования библиотеки \texttt{calculator.jar} были получены следующие результаты:

    \begin{enumerate}
        \item \textbf{Тестирование метода сложения (SumTests)}:
        \begin{itemize}
            \item Все тесты корректности сложения для целых чисел и чисел с плавающей точкой прошли успешно
            \item Операции с граничными значениями (максимальные/минимальные значения \texttt{long} и \texttt{double}) выполняются без переполнения
            \item Особые случаи (сложение с нулем) соответствуют ожидаемым результатам.
        \end{itemize}
        \item \textbf{Тестирование метода умножения (MulTests)}:
        \begin{itemize}
            \item Метод для умножения целых чисел прошёл все тесты.
            \item Метод для умножения чисел с плавающей точкой прошёл 1 из 4 тестов.
        \end{itemize}
        
        \item \textbf{Тестирование метода квадратного корня (SqrtTests)}:
        \begin{itemize}
            \item Метод прошёл 3 из 4 тестов.
            \item Метод корректно обрабатывает положительные значения и 0.
            \item Отрицательные числа обрабатываются некорректно. Вместо того, чтобы вернуть ошибку или \texttt{NaN}, метод вычисляет значения корня по модулю числа.
        \end{itemize}
        
        \item \textbf{Тестирование метода тангенса (tgTests)}:
        \begin{itemize}
            \item Метод прошёл 1 из 5 тестов.
            \item Функция тангенса фактически всегда возвращает 1 (кроме случаев, когда \texttt{sin(a) = 0})
            \item Свойство нечетности (\texttt{tg(-x) = -tg(x)}) не соблюдается, значение \texttt{tg(x)} равно 1.
            \item Функция возвращает неккоректное значение при попытке вычислить \texttt{tg(0)}. При вычислении возваращется \texttt{NaN}, а не 0, как ожидается.
        \end{itemize}
    
    \item \textbf{Общие выводы:}
    
    Два из четырёх тестируемых методов не прошли все тесты. В реализации методов умножения и вычисления тангенса присутствуют ошибки.

    Метод умножения неккоректно работает с дробными числами. А метод для вычисления тангенса возвращает 1 для любого входного значения, кроме 0. При нулевом входном значении метод возвращает \texttt{NaN}.
    \end{enumerate}

    \newpage
    \subsection{Работа №2}
В ходе выполнения работы №2 необходимо было реализовать два теста для тестирования web-сайта с помощью библиотеки Selenium WebDriver. Тесты должны проверять, что элементы сайта \texttt{https://jdi-testing.github.io/jdi-light/index.html} отображаются корректно и позволяют взаимодействовать с собой правильным образом. Реализация тестов должна быть выполнена согласно Java Code Convention и запускаться с помощью TestNG suite xml.\par

Тесты разделяются на 2 класса, в которых необходимо реализовать тесты, связанные с взаимодействием сайта.

В первом наборе тестов необходимо проверить корректность отображения страницы. Все сценарии, которые необходимо проверить, представлены в \hyperref[tab1]{таблице 1}

\begin{table}[h!]
    \centering
    \label{tab1}
    \caption{\centering{Тест-кейсы для веб-приложения (с использованием SoftAsserts)}}
    \footnotesize
    \begin{tabularx}{\textwidth}{|c|>{\centering\arraybackslash}X|>{\centering\arraybackslash}X|>{\centering\arraybackslash}X|}
        \hline
        № & Шаг тестирования & Данные & Ожидаемый результат \\
        \hline
        1 & Открыть тестовый сайт по URL & \url{https://jdi-testing.github.io/jdi-light/index.html} & Тестовый сайт открыт \\
        \hline
        2 & Проверить заголовок браузера & "Home Page" & Заголовок соответствует "Home Page" \\
        \hline
        3 & Выполнить вход в систему & Логин: Roman, Пароль: Jdi1234 & Пользователь авторизован \\
        \hline
        4 & Проверить отображение имени пользователя & "ROMAN IOVLEV" & Имя отображается корректно \\
        \hline
        5 & Проверить пункты меню в шапке & "HOME", "CONTACT FORM", "SERVICE", "METALS \& COLORS" & 4 пункта меню с правильным текстом \\
        \hline
        6 & Проверить изображения на странице & 4 изображения & Все изображения отображаются \\
        \hline
        7 & Проверить тексты под иконками & 4 текстовых блока & Тексты соответствуют ожидаемым \\
        \hline
        8 & Проверить наличие iframe & Кнопка "Frame Button" & iframe существует \\
        \hline
        9 & Проверить кнопку во фрейме & - & Кнопка "Frame Button" доступна \\
        \hline
        10 & Вернуться в основное окно & - & Фокус на основном окне \\
        \hline
        11 & Проверить левое меню & "Home", "Contact form", "Service", "Metals \& Colors", "Elements packs" & 5 пунктов меню с правильным текстом \\
        \hline
        12 & Закрыть браузер & - & Браузер закрыт \\
        \hline
    \end{tabularx}
\end{table}\par
Во втором наборе тестов необходимо проверить корректность взаимодействия пользователя с сайтом (в частности, правильность выбора чекбоксов, радиобаттонов и элементов из выпадающего списка).
Таблица тестов, необходимых к реализации во втором упражнении, представлена в \hyperref[tab2]{таблице 2}.

\begin{table}[h!]
    \centering
    \label{tab2}
    \caption{\centering{Тест-кейсы для веб-приложения (с использованием SoftAsserts)}}
    \footnotesize
    \begin{tabularx}{\textwidth}{|c|>{\RaggedRight\arraybackslash}X|>{\RaggedRight\arraybackslash}X|>{\RaggedRight\arraybackslash}X|}
        \hline
        \ № & Шаг тестирования (Testing Step) & Данные (Data) & Ожидаемый результат (Expected Result) \\
        \hline
        1 & Открыть тестовый сайт по URL & \url{https://jdi-testing.github.io/jdi-light/index.html} & Тестовый сайт открыт (Test site is opened) \\
        \hline
        2 & Проверить заголовок браузера (Check browser title) & "Home Page" & Заголовок соответствует "Home Page" (Title matches "Home Page") \\
        \hline
        3 & Выполнить вход в систему (Perform login) & username: Roman, password: Jdi1234 & Пользователь авторизован (User is logged in) \\
        \hline
        4 & Проверить отображение имени пользователя (Verify username display) & "ROMAN IOVLEV" & Имя отображается корректно (Name is displayed correctly) \\
        \hline
        5 & Открыть через хедер меню Service -> Different Elements Page (Navigate using header menu: Service -> Different Elements Page) & & Страница открыта (Page is opened) \\
        \hline
        6 & Выбрать чекбоксы (Select checkboxes) & Water, Wind & Элементы отмечены (Elements are checked) \\
        \hline
        7 & Выбрать переключатель (Select radio) & Selen & Элемент отмечен (Element is selected) \\
        \hline
        8 & Выбрать в один из выпадающего списка (Select in dropdown) & Yellow & Элемент выбран (Element is chosen) \\
        \hline
        9 & Проверить, что для каждого чекбокса, radio и dropdown есть отдельная строчка лога (Verify that for each checkbox, radio, and dropdown there is a separate log row) & & Логи отображаются и соответствуют выбранным значениям (Logs are displayed and correspond to selected values) \\
        \hline
        10 & Закрыть браузер (Close browser) & & Браузер закрыт (Browser is closed) \\
        \hline
    \end{tabularx}
\end{table}
\subsubsection{Класс DriverSetup}
Класс \texttt{DriverSetup} выполняет первоначальную настройку \texttt{WebDriver} перед запуском тестов. Он устанавливает системные свойства для Chrome Driver, настраивает HTTP клиент и создает экземпляр Chrome Driver, открывая тестовый сайт и выполняет авторизацию пользователя.

\begin{lstlisting}[label= list5, caption=\ ]
public class DriverSetup {
    protected static WebDriver driver;

    @BeforeTest
    public static void setup() {
        System.setProperty("webdriver.chrome.driver", "src/test/resources/chromedriver.exe");
        System.setProperty("webdriver.http.factory", "jdk-http-client");

        driver = new ChromeDriver();

        driver.navigate().to("https://jdi-testing.github.io/jdi-light/index.html");

        driver.findElement(By.cssSelector("html > body > header > div > nav > ul.uui-navigation.navbar-nav.navbar-right > li > a > span")).click();
        driver.findElement(By.id("name")).sendKeys("Roman");
        driver.findElement(By.id("password")).sendKeys("Jdi1234");
        driver.findElement(By.id("login-button")).click();
    }

    @AfterTest
    public static void exit() {
        driver.close();
    }
}
\end{lstlisting}

Класс содержит следующие элементы:
\begin{itemize}
    \item \textbf{driver}: Защищенная статическая переменная типа WebDriver, представляющая экземпляр браузера Chrome, используемый для выполнения тестов.
    \item \textbf{@BeforeTest setup()}: Статический метод, помеченный аннотацией @BeforeTest, выполняемый перед всеми тестовыми методами. Он выполняет следующие действия:
    \begin{itemize}
        \item Устанавливает системные свойства `webdriver.chrome.driver` и `webdriver.http.factory`.
        \item Создает экземпляр `ChromeDriver`.
        \item Открывает тестовый сайт по URL: \url{https://jdi-testing.github.io/jdi-light/index.html}.
        \item Выполняет вход в систему, находя и заполняя поля логина и пароля, а также нажимая кнопку входа.
    \end{itemize}
    \item \textbf{@AfterTest exit()}: Статический метод, помеченный аннотацией `@AfterTest`, выполняемый после всех тестовых методов. Он закрывает браузер с помощью `driver.close()`.
\end{itemize}
\subsubsection{Класс Task1Test}
Класс \texttt{Task1Test} является тестовым классом, который выполняет проверки различных элементов на главной странице веб-сайта. Для проверки ожидаемых результатов используются "мягкие" утверждения (SoftAsserts), что позволяет продолжить выполнение теста даже в случае неудачи одного из утверждений.

\begin{lstlisting}[language=Java, caption=Класс Task1Test, basicstyle=\footnotesize\ttfamily, breaklines=true]
package edu.hsai.homework2;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.testng.annotations.Test;
import org.testng.asserts.SoftAssert;

import java.util.List;

public class Task1Test extends DriverSetup {
    @Test
    public void testTask1() {
        SoftAssert softAssert = new SoftAssert();

        softAssert.assertEquals(driver.getTitle(), "Home Page");

        softAssert.assertEquals(driver.findElement(By.id("user-name")).getText(), "ROMAN IOVLEV");

        List<WebElement> headerItems = driver.findElements(By.cssSelector("ul.uui-navigation.nav > li"));
        softAssert.assertEquals(headerItems.size(), 4);

        String[] expectedHeaderTexts = {"HOME", "CONTACT FORM", "SERVICE", "METALS & COLORS"};
        for (int i = 0; i < headerItems.size(); i++) {
            softAssert.assertTrue(headerItems.get(i).isDisplayed());
            softAssert.assertEquals(headerItems.get(i).getText(), expectedHeaderTexts[i]);
        }

        List<WebElement> images = driver.findElements(By.cssSelector(".benefit-icon > span"));
        softAssert.assertEquals(images.size(), 4);
        for (WebElement image : images) {
            softAssert.assertTrue(image.isDisplayed());
        }

        List<WebElement> texts = driver.findElements(By.className("benefit-txt"));
        softAssert.assertEquals(texts.size(), 4);

        String[] expectedTexts = {
            "To include good practices\nand ideas from successful\nEPAM project",
            "To be flexible and\ncustomizable",
            "To be multiplatform",
            "Already have good base\n (about 20 internal and \n some external projects), \n wish to get more..."
        };

        for (int i = 0; i < texts.size(); i++) {
            softAssert.assertEquals(texts.get(i).getText(), expectedTexts[i]);
        }

        WebElement iframe = driver.findElement(By.id("frame"));
        softAssert.assertTrue(iframe.isDisplayed());

        driver.switchTo().frame(iframe);
        WebElement frameButton = driver.findElement(By.id("frame-button"));
        softAssert.assertTrue(frameButton.isDisplayed());

        driver.switchTo().defaultContent();

        List<WebElement> leftMenuItems = driver.findElements(By.cssSelector("ul.sidebar-menu.left > li"));
        softAssert.assertEquals(leftMenuItems.size(), 5);

        String[] expectedMenuTexts = {"Home", "Contact form", "Service", "Metals & Colors", "Elements packs"};
        for (int i = 0; i < leftMenuItems.size(); i++) {
            WebElement item = leftMenuItems.get(i);
            softAssert.assertTrue(item.isDisplayed());
            softAssert.assertEquals(item.getText(), expectedMenuTexts[i]);
        }

        softAssert.assertAll();
    }
}
\end{lstlisting}

Класс содержит следующие основные компоненты:

\begin{itemize}
    \item \textbf{Наследование от DriverSetup}: Класс \texttt{Task1Test} наследуется от класса \texttt{DriverSetup}, который выполняет предварительную настройку WebDriver и открывает веб-сайт.
    \item \textbf{@Test testTask1()}: Это тестовый метод, помеченный аннотацией \texttt{@Test}, который указывает, что это метод TestNG для выполнения тестов.
    \item \textbf{SoftAssert softAssert = new SoftAssert()}: Создание экземпляра \texttt{SoftAssert}, который позволяет собирать ошибки и не останавливать выполнение теста при первой неудаче.
    \item \textbf{Проверки (Assertions)}: Метод содержит ряд проверок с использованием \texttt{softAssert.assertEquals()} и \texttt{softAssert.assertTrue()} для проверки различных элементов веб-страницы:
    \begin{itemize}
        \item Заголовок страницы (\texttt{softAssert.assertEquals(driver.getTitle(), "Home Page")})).
        \item Имя пользователя (\texttt{softAssert.assertEquals(driver.findElement(By.id("user-name")).getText(), "ROMAN IOVLEV")})).
        \item Элементы в секции заголовка (количество и текст элементов меню).
        \item Изображения на главной странице (количество и отображение).
        \item Тексты под иконками (количество и соответствие ожидаемым текстам).
        \item Наличие и отображение iframe.
        \item Наличие и отображение кнопки во iframe.
        \item Элементы в левом меню (количество и текст элементов).
    \end{itemize}
    \item \textbf{Переключение на iframe и обратно}: В коде происходит переключение на iframe для проверки содержимого внутри него, а затем возврат обратно к основному содержанию страницы.
    \item \textbf{softAssert.assertAll()}: Вызов этого метода в конце тестового метода позволяет убедиться, что все собранные ошибки будут выведены, и тест завершится с соответствующим статусом.
\end{itemize}

\subsubsection{Класс Task2Test}
Класс \texttt{Task2Test} является тестовым классом, который проверяет различные элементы и функциональности веб-сайта. Он использует библиотеку Selenium WebDriver для взаимодействия с веб-страницей и библиотеку TestNG для организации и выполнения тестов. Класс выполняет проверку заголовка страницы, имени пользователя, а также взаимодействует с элементами на странице "Different Elements" (чекбоксы, радиокнопки, выпадающий список) и проверяет логи.

\begin{lstlisting}[language=Java, caption=Класс Task2Test, basicstyle=\footnotesize\ttfamily, breaklines=true]
public class Task2Test extends DriverSetup {
    private static final By USER_NAME = By.id("user-name");

    @Test
    public void testBrowserTitle() {
        assertEquals(driver.getTitle(), "Home Page", "Browser title should be 'Home Page'");
    }

    @Test
    public void testLogin() {
        WebElement userNameElement = new WebDriverWait(driver, Duration.ofSeconds(10))
        .until(ExpectedConditions.visibilityOfElementLocated(USER_NAME));

        assertTrue(userNameElement.isDisplayed(), "Username should be displayed");
        assertEquals(userNameElement.getText(), "ROMAN IOVLEV", "Username should be 'ROMAN IOVLEV'");
    }

    @Test
    public void testElements() {
        WebElement serviceDropdown = driver.findElement(By.cssSelector("header .nav > li.dropdown"));
        serviceDropdown.click();

        WebElement differentElementsLink = driver.findElement(By.xpath("//a[text()='Different elements']"));
        differentElementsLink.click();
        assertEquals(driver.getTitle(), "Different Elements", "Заголовок страницы 'Different Elements' неверный.");

        List<String> checkboxesToSelect = Arrays.asList("Water", "Wind");
        List<WebElement> checkboxes = new WebDriverWait(driver, Duration.ofSeconds(10))
        .until(ExpectedConditions.visibilityOfAllElementsLocatedBy(
        By.cssSelector(".label-checkbox")
        ));

        for (WebElement checkbox : checkboxes) {
            if (checkboxesToSelect.contains(checkbox.getText())) {
                if (!checkbox.findElement(By.tagName("input")).isSelected()) {
                    checkbox.click();
                }
                assertTrue(checkbox.findElement(By.tagName("input")).isSelected());
            }
        }

        String radioToSelect = "Selen";
        List<WebElement> radios = new WebDriverWait(driver, Duration.ofSeconds(10))
        .until(ExpectedConditions.visibilityOfAllElementsLocatedBy(
        By.cssSelector(".label-radio")
        ));

        for (WebElement radio : radios) {
            if (radio.getText().equals(radioToSelect)) {
                radio.click();
                assertTrue(radio.findElement(By.tagName("input")).isSelected());
                break;
            }
        }

        String dropdownValueToSelect = "Yellow";
        WebElement dropdown = new WebDriverWait(driver, Duration.ofSeconds(10))
        .until(ExpectedConditions.elementToBeClickable(
        By.cssSelector(".colors select")
        ));

        Select select = new Select(dropdown);
        select.selectByVisibleText(dropdownValueToSelect);
        assertEquals(select.getFirstSelectedOption().getText(), dropdownValueToSelect);

        List<WebElement> logs = new WebDriverWait(driver, Duration.ofSeconds(10))
        .until(ExpectedConditions.visibilityOfAllElementsLocatedBy(
        By.cssSelector(".logs li")
        ));
        for (var elem : logs)
        System.out.println(elem.getText());

        List<String> expectedLogs = Arrays.asList(
        "Water: condition changed to true",
        "Wind: condition changed to true",
        "metal: value changed to Selen",
        "Colors: value changed to Yellow"
        );

        for (int i = 0; i < expectedLogs.size(); i++) {
            String actualLog = logs.get((logs.size()-1) - i).getText().replaceAll("\\d{2}:\\d{2}:\\d{2}", "").trim();
            assertTrue(actualLog.endsWith(expectedLogs.get(i)));
        }
    }
}
\end{lstlisting}

Класс содержит следующие основные компоненты:

\begin{itemize}
    \item \textbf{Наследование от DriverSetup}: Класс \texttt{Task2Test} наследуется от класса \texttt{DriverSetup}, который выполняет предварительную настройку WebDriver и открывает веб-сайт.
    \item \textbf{Поле USER\_NAME}: Приватное статическое поле \texttt{USER\_NAME} типа \texttt{By}, содержащее локатор для элемента с именем пользователя.
    \item \textbf{@Test testBrowserTitle()}: Тестовый метод, который проверяет заголовок браузера на соответствие значению "Home Page". Использует \texttt{assertEquals} для проверки.
    \item \textbf{@Test testLogin()}: Тестовый метод, который проверяет, что имя пользователя отображается и соответствует ожидаемому значению "ROMAN IOVLEV". Использует явное ожидание (\texttt{WebDriverWait}) для проверки видимости элемента.
    \item \textbf{@Test testElements()}: Тестовый метод, который выполняет следующие шаги:
    \begin{itemize}
        \item Открывает страницу "Different Elements" через меню "Service".
        \item Выбирает чекбоксы "Water" и "Wind".
        \item Выбирает радиокнопку "Selen".
        \item Выбирает значение "Yellow" в выпадающем списке.
        \item Проверяет логи на соответствие ожидаемым значениям.
    \end{itemize}
    \item \textbf{Явные ожидания (WebDriverWait)}: Используются для ожидания появления и кликабельности элементов, что делает тесты более стабильными.
    \item \textbf{Проверка логов}: Код проверяет логи на соответствие ожидаемым значениям, учитывая порядок и формат записей.
\end{itemize}
\subsubsection{Результаты работы №2}
Результаты запуска тестов представлены на Рис.~\ref{fig:selenium-tests}

\begin{figure}[h!]
   \centering
   \includegraphics[width=0.35\linewidth]{img/selenium-tests.png}
   \caption{Результаты выполнения тестов Selenium WebDriver}
   \label{fig:selenium-tests}
\end{figure}

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



    \newpage
    \section*{Заключение}
    \addcontentsline{toc}{section}{Заключение}
	
	В ходе выполнения лабораторной работы были изучены ключевые аспекты автоматизированного тестирования программного обеспечения. Работа охватила создание, написание и выполнение юнит-тестов для Java-библиотеки calculator.jar с использованием JUnit, а также организацию тестирования веб-страниц с помощью Selenium WebDriver и TestNG.
	
	В результате тестирования библиотеки calculator.jar были обнаружены неточности в реализации некоторых методов, в частности, неверное вычисление тангенса и некорректная работа с числами с плавающей точкой при умножении. Эти ошибки могли бы остаться незамеченными при поверхностном ручном тестировании, что демонстрирует ценность автоматизированного подхода.
	
	При тестировании веб-сайта с помощью Selenium WebDriver была подтверждена корректность отображения элементов и их функциональность. Успешное прохождение всех тестов показало, что сайт работает в соответствии с ожиданиями в тестовых сценариях.
	
	Использованные инструменты автоматизированного тестирования продемонстрировали себя как эффективное средство для систематической проверки программного обеспечения на соответствие требованиям. Они позволяют выполнять тесты на больших наборах данных и многократно повторять одни и те же сценарии, что затруднительно при ручном тестировании.
	
	Тем не менее, автоматизированное тестирование имеет свои ограничения. Оно фокусируется преимущественно на проверке функциональности и не способно в полной мере оценить удобство использования или обнаружить непредвиденные сценарии использования. Кроме того, сами автоматизированные тесты могут содержать ошибки.
	
	Таким образом, можно заключить, что наиболее эффективный подход к тестированию сочетает в себе автоматизированные и ручные методы. Автоматизированное тестирование обеспечивает стабильность и повторяемость проверок, а ручное позволяет выявлять проблемы, связанные с удобством использования и нестандартными сценариями. Комплексное применение обоих подходов существенно повышает качество программного обеспечения.

\newpage
\section*{Список литературы}
\addcontentsline{toc}{section}{Список литературы}

\vspace{-1.5cm}
\begin{thebibliography}{0}
    \bibitem{1} {Что такое Selenium WebDriver? — Habr. [Электронный ресурс]. \\URL: \href{https://habr.com/ru/articles/152971/}{https://habr.com/ru/articles/152971/} (дата обращения: 30.04.2025).}
		
    \bibitem{2} {Selenium IDE — Habr. [Электронный ресурс]. \\URL: \href{https://habr.com/ru/articles/590607/}{https://habr.com/ru/articles/590607/} (дата обращения: 30.04.2025).}
\end{thebibliography}

\end{document}