- PVSM.RU - https://www.pvsm.ru -
Это не руководство, какие символы нужно ввести в редакторе кода, чтобы получились модульные тесты. Это — пища для ума, которую необходимо употребить до того, как предпринимать упомянутые действия.
Тема модульного тестирования не так проста, как может показаться. Многие из нас, разработчиков, приходят в модульное тестирование под давлением клиентов, сотрудников, коллег, своих кумиров и так далее. Мы быстро понимаем его ценность, и, закончив технические приготовления, забываем об общей картине, если вообще когда-либо её понимали. В этой статье я вкратце расскажу о том, чем является и чем не является модульное тестирование как в целом, так и в PHP, а заодно опишу, какое место занимает модульное тестирование в сфере QA.
Прежде чем углубляться в модульные тесты, нужно изучить теорию самого тестирования, чтобы не делать ошибок вроде той, что совершили авторы одного из самых популярных PHP-фреймворков: на своём сайте они показали интеграционные тесты и назвали [1]их модульными. Нет, Laravel, это не модульные тесты. Хотя это не мешает мне всё ещё любить этот фреймворк.
Тестирование ПО определяется [2]как «расследование, проведённое с целью предоставления заинтересованным сторонам информации о качестве продукта». Этому противопоставляется «тестирование ПО — это пустая трата бюджета проекта разработчиками, которые не делают ничего важного, а затем просят ещё времени и денег, потому что «ничего» может быть весьма дорогим». Тут ничего нового.
Вот моя краткая история становления тестирования:
Если вы относитесь к поколению миллениалов, как я, то, возможно, будете поражены, что команды тестировщиков существовали ЗАДОЛГО до вашего рождения. Остановитесь на минутку, вдохните, выдохните, успокойтесь.
История показывает, как в течение времени менялся тип тестирования, которое считалось «достаточно хорошим» для заинтересованных сторон. Примерные фазы, на что ориентировались при тестировании:
Следовательно, модульное тестирование необходимо для предотвращения несоответствий между проектом и реализацией.
Есть разные классификации тестирования ПО. Чтобы лучше понимать место модульного тестирования, упомяну лишь о наиболее широкораспространённых подходах.
Тесты бывают: статические и динамические, «ящичные» (белый ящик, чёрный ящик, серый ящик), уровни и типы. В рамках каждого подхода используются разные критерии классификации.
Статическое тестирование проводится без исполнения кода. Сюда относится корректура, проверка, ревизия кода (при наблюдении за работой другого / парном программировании), критический анализ, инспекции и так далее.
Динамическое тестирование для получения корректных результатов требует исполнять код. Например, для модульных тестов, интеграционных, системных, приёмочных и прочих тестов. То есть тестирование проводится с использованием динамических данных, входных и выходных.
Согласно этому подходу, все тесты ПО делятся на три вида ящиков:
Теперь, чтобы запутать вас, скажу, что модульное тестирование может относиться и к «чёрному ящику», поскольку вы можете разбираться в тестируемом модуле, но не во всей системе. Хотя для меня оно по-прежнему «белый ящик», и предлагаю вам с этим согласиться.
Их количество варьируется, обычно, в диапазоне от 4 до 6, и все они полезны. Названия тоже бывают разные, в зависимости от принятой в компании культуры вы можете знать «интеграционные» тесты как «функциональные», «системные» тесты как «автоматизированные», и так далее. Для простоты я опишу 5 уровней:
Модульное тестирование проверяет функциональность конкретного куска кода, обычно по одной функции за раз. Интеграционное тестирование проверяет интерфейсы между компонентами, чтобы собранные воедино модули формировали систему, работающую, как задумано. Это важный момент, потому что большое количество тестов, которые называют модульными, на самом деле являются интеграционными тестами, а разработчики считают их модулями. Если подразумевается использование нескольких модулей — это тестирование интеграции между ними, а не самих модулей. Тестирование интерфейсов компонентов проверяет данные, передаваемые между разными модулями. Например, получили данные из модуля 1 — проверили — передали в модуль 2 — проверили. Системное тестирование — это сквозное тестирование ради проверки соблюдения всех требований. Эксплуатационное приёмочное тестирование выполняется для проверки готовности к эксплуатации. Оно не является функциональным, проверяется лишь работоспособность сервисов, не повреждают ли какие-то подсистемы среду и прочие сервисы.
Каждый тип тестирования, вне зависимости от его уровня, также может подразделяться на другие типы. Существует больше 20 общепринятых типов. Самые распространённые:
Из названия понятно, для чего предназначен тот или иной тип тестирования. Жирным выделены модульные тесты в PHP. Если очень хочется, то к модульному тестированию можно применить каждый из этих терминов. Однако главной разновидностью модульных тестов являются тесты регрессионные, которые проверяют, все ли модули системы исполняются корректно после внесения изменений в код.
Теперь вы знаете, что модульные тесты являются динамическими, относятся к классу «белый ящик», выполняются на уровне модулей, представляют собой регрессионные тесты, но при этом под модульными тестами можно понимать многие разновидности тестов. Так что же такое на самом деле модульные тесты?
V-модель — это графическое представление вышеупомянутых уровней, типов и их назначения в жизненном цикле разработки ПО.
После проверки и утверждения подробных требований к продукту, когда уже начали писать код, первой линией защиты от любых несоответствий становятся модульные тесты. Поэтому компании, понимающие, что они делают, заставляют разработчиков использовать модульные тесты или даже TDD, поскольку гораздо дешевле исправить баги на начальных этапах, чем на более поздних.
И это справедливо. У модульных тестов масса достоинств. Они:
Однако, есть определённые ограничения, о которых вы подумали, вероятно, при чтении этого списка:
Последнее убивает меня больше всего. (Почти) в каждом проекте прямо в исходном коде рабочего приложения я нахожу строки наподобие «если это модульный тест, грузить суррогатную SQLite базу данных, в противном случае грузить другую БД», или «если это модульный тест, не отправлять письмо, в противном случае отправлять», и так далее. Если у вашего приложения плохая архитектура, не притворяйтесь, что можете исправить паршивое ПО с помощью хорошего прохождения тестов, оно от этого не станет лучше.
Я часто обсуждал с коллегами и клиентами, что такое хороший модульный тест. Он:
Тем, кто ухмыльнулся, прочитав «автоматизированный»: я не имел в виду интегрирование PHPUnit или JUnit в CI-конвейеры. Речь идёт о том, что если вы меняете код, сохраняете его и не знаете, проходят ли модули свои тесты, то они не автоматизированы, а должны бы. Выигрышный вариант — отслеживание файлов (File watcher).
В нормальных системах модульные тесты нужно писать для:
Определение модульного теста зависит от разработчика, написавшего код. В PHP это почти всегда метод класса или функция, потому что это неделимая часть ПО, имеющая смысл сама по себе. Несколько раз я видел, как разработчики в качестве одного модуля использовали массив из однометодных миниклассов. Это имеет смысл, если минимальная функциональность требует наличия нескольких объектов.
Так что вы сами можете определять, что для вас является модулем. Или можете тестировать методы один за другим, упростив жизнь тому парню, что потом будет работать с кодом.
Если вы не проводите модульное тестирование, предлагаю заняться этим после возникновения следующего большого бага. Проверьте, с каким методом он будет связан, напишите сбойный тест с правильными аргументами и результатом, исправьте баг, снова запустите модульный тест. Если он будет пройден, то можете быть уверены, что этот баг пришлось исправлять в последний раз (с учётом ваших определённых входных сценариев).
Такой подход помогает легче понять модульное тестирование. Проанализируйте отдельно каждый метод. Поставщики данных могут помочь определить входные и выходные данные для любых сценариев, которые могут прийти вам в голову, поэтому что бы ни произошло, вы будете знать, чего ожидать.
Чуть сложнее определить, что тестировать не нужно. Я постарался собрать список элементов, которые не нужно подвергать модульному тестированию:
Уверен, не следует применять модульное тестирование ни к чему из вышеперечисленного, кроме статичных методов. Мне нравится аргументировать, что статичность, по сути, означает процедуральность, причём в многих случаях процедуральность глобальную. Если статичный метод вызывает другой статичный метод, то эту зависимость нельзя переопределить. А это значит, что вы теперь тестируете не изолированно. И тогда это уже не модульное тестирование. С другой стороны, это же часть кода, которая может жить сама по себе, у неё есть предназначение, и её нужно тестировать, чтобы удостовериться: какую бы часть этой бестолковой системы ни вызвала тестируемая часть кода, та не сломается. Поэтому считаю, что тестировать статичные методы можно, если вы уверены, что выходные данные вашего теста не сможет изменить никакой другой тест, и что язык или фреймворк позволят тестировать нативно.
Если «затем тестируйте его» недостаточно, то на laracasts.com [4] есть очень хорошие видео про модульное тестирование PHP. Есть и масса сайтов, посвящённых той же задаче в других языках. Не вижу смысла объяснять, как я выполняю модульное тестирование, потому что инструменты меняются довольно быстро, и когда вы прочитаете этот текст, я могу переключиться с PHPUnit на Kahlan. Или нет. Кто знает.
Но ответить на первый вопрос (как писать код, пригодный для модульного тестирования) гораздо легче, и вряд ли ситуация сильно изменится со временем:
Теперь, зная, чем являются и чем не являются модульные тесты, что нужно и что не нужно тестировать, какое место занимают модульные тесты в жизненном цикле разработки ПО, вам будет легче реализовывать их. Осталось найти фреймворк или библиотеку по душе. Если сомневаетесь, берите фреймворк/язык, ставший стандартом де-факто.
В заключение: модульные тесты очень важны как для разработчиков, так и для бизнеса. Их нужно писать, существуют отработанные методики, которые помогут вам легко покрыть модули тестами, в основном с помощью подготовки самих модулей. Но все эти методики не имеют смысла без знания теории тестирования, описанной в этой статье. Нужно уметь отличать модульные тесты от тестов других типов. И когда у вас в голове будет ясное понимание, то и писать тесты вам станет гораздо легче.
Автор: Макс
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/php-2/282169
Ссылки в тексте:
[1] назвали : https://laravel.com/docs/5.0/testing
[2] определяется : https://en.wikipedia.org/wiki/Software_testing#cite_note-Kaner_1-1
[3] Walkthrough: https://en.wikipedia.org/wiki/Software_walkthrough
[4] laracasts.com: https://laracasts.com/
[5] Источник: https://habr.com/post/412695/?utm_source=habrahabr&utm_medium=rss&utm_campaign=412695
Нажмите здесь для печати.