diff --git a/lab4/.gitignore b/lab4/.gitignore new file mode 100644 index 0000000..27fa349 --- /dev/null +++ b/lab4/.gitignore @@ -0,0 +1 @@ +other \ No newline at end of file diff --git a/lab4/report/.gitignore b/lab4/report/.gitignore new file mode 100644 index 0000000..8bbef0e --- /dev/null +++ b/lab4/report/.gitignore @@ -0,0 +1,7 @@ +**/* +!.gitignore +!report.tex +!img +!img/** +!programm +!programm/*.py \ No newline at end of file diff --git a/lab4/report/img/selenium-tests.png b/lab4/report/img/selenium-tests.png new file mode 100644 index 0000000..625203d Binary files /dev/null and b/lab4/report/img/selenium-tests.png differ diff --git a/lab4/report/img/test1.png b/lab4/report/img/test1.png new file mode 100644 index 0000000..903d3db Binary files /dev/null and b/lab4/report/img/test1.png differ diff --git a/lab4/report/img/test2.png b/lab4/report/img/test2.png new file mode 100644 index 0000000..3e2434b Binary files /dev/null and b/lab4/report/img/test2.png differ diff --git a/lab4/report/img/test3.png b/lab4/report/img/test3.png new file mode 100644 index 0000000..7890189 Binary files /dev/null and b/lab4/report/img/test3.png differ diff --git a/lab4/report/img/test4.png b/lab4/report/img/test4.png new file mode 100644 index 0000000..cf0b708 Binary files /dev/null and b/lab4/report/img/test4.png differ diff --git a/lab4/report/report.tex b/lab4/report/report.tex new file mode 100644 index 0000000..0af92e7 --- /dev/null +++ b/lab4/report/report.tex @@ -0,0 +1,845 @@ +\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(Math.abs(value)); + assertEquals(expected, calculator.sqrt(value), DELTA); +} +\end{lstlisting} + + \textbf{Результаты запуска тестов:} + + Результаты запуска тестов представлены на рисунке \ref{fig:test3}. + + \begin{figure}[h!] + \centering + \includegraphics[width=0.35\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 Метод прошёл все 4 теста. + \item Метод корректно обрабатывает положительные, отрицательные значения и 0. + \item Отрицательные числа обрабатываются через модуль (\texttt{Math.abs}) + \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 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 images = driver.findElements(By.cssSelector(".benefit-icon > span")); + softAssert.assertEquals(images.size(), 4); + for (WebElement image : images) { + softAssert.assertTrue(image.isDisplayed()); + } + + List 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 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 checkboxesToSelect = Arrays.asList("Water", "Wind"); + List 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 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 logs = new WebDriverWait(driver, Duration.ofSeconds(10)) + .until(ExpectedConditions.visibilityOfAllElementsLocatedBy( + By.cssSelector(".logs li") + )); + for (var elem : logs) + System.out.println(elem.getText()); + + List 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} \ No newline at end of file