Введение
Разберемся немного в терминологии:
Функциональное (E2E) тестирование — проверка, что сценарии работы пользователя выполняются. Другими словами прогоны тестовых пользовательский сценариев. Поддерживается фреймворками "Сценарное тестирование", "Vanessa-ADD", "Vanessa-Automation", "Тестер" и др. Большинство из этих фреймворков специально созданы для написания функциональных/сценарных тестов.
Unit-тестирование (модульное тестирование) — проверка на корректность отдельные единицы работы исходного кода программы. Минимальными единицами работы для нас являются процедуры и функции.
Получилось так, что наибольшую популярность среди программистов 1С получило функциональное тестирование. Такой вывод можно сделать по обилию публикаций и дискуссий на профессиональных конференциях.
Основной целью такого тестирования при его внедрении в первую очередь является уменьшение ошибок, в том числе организация регрессионного тестирования (англ. regression testing, собирательное название для всех видов тестирования программного обеспечения, направленных на обнаружение ошибок в уже протестированных участках исходного кода).
Функциональное тестирование требует подготовки — создание эталонных баз / шаблонов данных, проработки сценариев использования и их написания. Т.е. это больше история про процесс разработки, а не непосредственное написание кода, ответственность за поддержку лежит на команде.
Unit-тесты в противовес функциональным тестам пишется разработчиком в помощь себе. Они позволяют быстро прогнать все возможные варианты входных данных для написанного участка кода, облегчают рефакторинг.
Для Unit-тестов есть один специализированный фреймворк — xUnitFor1C (возможно я не прав, напишите, пожалуйста, в комментариях, если это не так). Его функционал плавно перекочевал в Vanessa-ADD. Также модульные тесты можно запускать и на фреймворках, предназначенных для функционального тестирования. Существуют плагин для EDT для написания unit-тестов с использованием фреймворка Vanessa-Automation (https://github.com/DoublesunRUS/ru.capralow.dt.unit.launcher).
Unit-тестирование и функциональное тестирование не исключают, а дополняют друг друга.
Функциональный тест vs Unit-тест
Попробуем сравнить разные виды тестирования.
Категории сравнения:
Скорость — время выполнения теста
Область действия — что тест проверяет
Сложность написания — объем необходимых знаний
Сложность запуска — насколько сложная инфраструктура нужна для запуска теста, насколько сложно обеспечить повторение однотипных тестов
Изменение трудозатрат на написание тестов с ростом количества тестов — как меняются количество времени, необходимое для написания тестов с ростом количества тестов и накоплением инструментария.
Критерий | Функциональный тест | Unit-тест |
Скорость | Медленный | Быстрый |
Область действия | Сценарий пользователя | Процедура/Функция |
Сложность написания | Средне | Средне |
Сложность запуска | Средне | Легко |
Трудозатраты на написание | Большие | Маленькие |
Изменение трудозатрат на написание тестов с ростом количества тестов | Уменьшаются | Остаются неизменными |
Скорость
Область действия
Тестовое покрытие функционального теста намного выше. Он проверяет сценарий пользователя, а следовательно и все процедуры/функции, вызываемые во время выполнения.
Unit-тест — обычно проверяет одну функцию или набор связанных процедур.
Сложность написания
C одной стороны Unit-тест писать достаточно легко за счет того, что его область действия очень маленькая. С другой не на всякую функцию unit-тест можно написать, функция должна быть "пригодна" для тестирования (об этом чуть дальше).
Функциональный тест можно записать "накликивая действия" в пользовательском интерфейсе. Большинство фреймворков позволяют преобразовать запись действий пользователя в сценарий, готовый к воспроизведению. К сожалению просто накликанные сценарии сложно поддерживать, приходится оптимизировать сгенерированный код. Да и забота о неизменности данных для тестов становится проблемой: не забывать удалять тестовые данные, делать так, чтобы данные для тестов не пересекались между собой непростая задача.
Сложность запуска
Unit-тест запускается одной кнопкой. Пишем код, запускаем тест.
Для функционального теста необходимо запуск как минимум несколько клиентов: менеджера тестирования и клиента тестирования. Иногда бывают проблемы с портами, по которым тест-менеджер общается с тест-клиентом или подключение тест-менеджер не сразу подключается к тест-клиенту.
Трудозатраты на написание
Первоначальные трудозатраты на написание функциональных тестов довольно большие — необходимо накопить библиотеку "шагов" (подсценариев), которые позволят в дальнейшем быстро писать более высокоуровневые сценарии.
Если пользовательский сценарий большой, то и данных в нем используется много, нужно быть готовым описывать их создание =)
Unit-тест тестирует небольшую функцию, обычно для тестирования функции объем данных намного меньше, чем для пользовательского сценария. Поэтому процесс описания алгоритма их создания займет немного времени.
Если вам нужен большой набор данных для Unit-теста, то скорее всего вы сделали что-то не так =)
Изменение трудозатрат на написание тестов с ростом количества тестов
Для функциональных тестов со временем копится подсценарии и новые тесты становится писать легче.
Для Unit-тестов фреймворк ADD/xUnit предоставляет богатый инструментарий и придумать того, что еще нет, довольно-таки сложно.
На что стоит писать Unit-тесты и что это дает
Удобно писать
- Расчетные механизмы
- Механизмы интеграции
- Любые API
Unit-тесты облегчают воспроизведение граничных случаев для отдельных функций и предоставляют возможность быстро протестировать поведение повторно.
Необходимость в таком тестировании чаще всего встречается в расчетных механизмах, при интеграциях со внешними сервисами, когда нужно протестировать большое количество вариантов входных данных.
Неудобно писать
- Отчеты
- Интерфейсы
Для теста отчета нужно много тестовых данных, в алгоритме их создания можно допустить много ошибок, да и легче это результат проверять функциональным тестом. Чтобы действительно хотелось тестировать локально — это формирование сложных ресурсов с большим количеством "ВычислитьВыражение" на разных уровнях группировок. Но пока для этого нет удобных инструментов =)
Интерфейсы нужно проверять с помощью функциональных тестов, будет быстрее и понятнее. Хотя на часть процедур в формах так и просится написать unit-тест, но необходимо потом аккуратно удалить, то что было создано. Не все инструменты позволяют это легко сделать.
Бессмысленно писать
- Обработки проведения документов
- Обработки проверки заполнения
- Печатные формы
- Отчеты
В этом классе задач огромное количество времени тратится на описание алгоритма формирования данных и конечный результат будет больше зависеть не от проверяемого кода, а ошибок, допущенных при создании тестовых данных. Писать Unit-тест, проверяющий алгоритм создание данных, дело крайне неблагодарное.
Вместо итога
Я попытался обобщить свой опыт написания Unit-тестов. Если у кого-то был другой опыт, было бы здорово, если бы вы рассказали о нём в комментариях =)
В этом посте было мало практический примеров. Этот недостаток постараюсь исправить вот тут: //infostart.ru/public/1085875/
(1)
Эта обработка проводит «дымовое тестирование». Такая возможность есть во многих фреймворках тестирования, которые указаны в статье
Её функционал несколько урезанный относительно аналогов — нельзя запускать на CI.
(1) А эта Ваш набор обработок не является ли набором обработок из раздела ERP ?
уж очень функционал схож.
или я ошибаюсь?
(0) Спасибо за набор статей с практическими примерами по тестированию.
Отдельное спасибо за использование и популяризацию Ванесса-АДД — тесты кодом (например, юнит-тесты) все-также важны!
Однозначно полезный материал, но вы пишите, что unit и сценарное дополняют друг-друга, а в статье делаете их противопоставление, сквозит мысль неудачного опыта сценарного тестирования 🙂
Но это разные техники и подходы, и TDD заслуживает внимания само по себе, а не от обратного других методик.
(6)
Целью статей было больше показать, что есть сценарии, в которых написание Unit-тестов позволит намного быстрее получить результат, чем при написании сценарных тестов.
Я сделал сравнение, потому что у меня сложилось мнение, что освоившие функциональное тестирование (которое благодаря удачным инструментам хорошо пошло в массы) категорично отметают модульное тестирование, не видят нишу его применения.
Вот я и попытался описать те ситуации, в которых unit-тест отлично себя показывает =) По крайней мере в моей практике =)
(7)
Да, я именно к этому и прицепился. Понимаете, механики тестирования у обоих подходов настолько отличаются, что даже тестируя казалось бы одну и туже функцию бизнес-приложения, о взаимозаменяемости говорить сложно. Юнит тест гарантирует работу определенного алгоритма, а сценарный — процесса. Юниту не нужно проверять срабатывания подписок на события или наличие объекта в меню, а сценарному, если и нужно только веб-сервис проверить, не менее важным является и достижимость функции в рамках процесса. В общем, хочу заразить идеей, что выставлять преимущества подхода лучше отталкиваясь от задачи, а не от неэффективности какой-либо другой методики.
(8) В рамках 1С «настоящие» юнит-тесты слабо возможны, т.к. наши тесты не отделимы от самой конфигурации 1С, платформы, СУБД и т.п.
я лично давно перестал употреблять термин именно » юнит-тестов», а использую термин «приемочные тесты» или «тесты кодом».
Любые приемочные тесты (хоть кодом (хЮнит, Тестер), хоть через БДД) имеют практическое одинаковые строение, как обычно, 3A 🙂
вопрос в инструментарии, удобстве разработки, сопровождаемости и т.п.
В рамках приемочных тестов в любом случае проверяются процессы. Только гранулярность этих процессов определяется разработчиком 🙂
лично я за последние годы практически не пишу тестов кодом, а использую возможности приемочного тестирования в виде БДД-сценариев.
при этом фактически работаю через механизмы ТДД/БДД.
(9) А вот это я не понял:
Речь о том, что тестируемый 1С-код редко когда бывает чисто unit-кодом? А чаще всего делает явные или неявные обращения за пределы модуля?
(10) в других языках программирования часто можно отделить бекграунд от самого класса и проверить только функциональность класса, например, не подключая СУБД, не вызывая веб-сервисы, какие-то конфигурационные действия и т.п.
В 1С с этим сложно, поле возможностей у нас поменьше.
всегда есть СУБД (файловая или настоящая), всегда есть платформа 1С, всегда есть конфигурации.
в идеале, как и в другом коде, лучше вводить спец.абстракции для отделения зависимостей друг от друга.
но это чаще всего имеет смысл только для модулей, а не для объектов конфигурации.
например, в большинстве случаев нет особого смысла абстрагироваться от объектной модели конфигурации, это усложняет логику.
(9)
По сравнению с другими языками это действительно так.
Но ведь можно представить что: у каждого метода языка есть параметры и есть контекст. Контекст — это параметры сеанса и методы доступа к БД.
Каждый метод нуждается не в полном контексте, а только в его части (кроме чего-то сильно глобального). И вот эту часть мы и можем мокать, создавая очень обрезанные объекты. Легкие, не требующие понимания а какие проверки нужно выполнить, чтобы он вообще создался.
Есть скажем контрагент, у него обязательно ИНН, КПП, заполненное по определенным правилам. Но в моем методе мне не нужен ИНН и КПП, мне нужна ссылка на контрагента и флаг «Не работаем», к примеру. И вот для модульного теста я и создам этого контрагента, не думая вообще ни о чем другом.
Да, это не полностью позволит мне проверить функционал, да я не проверю что процесс дойдет до конца. Но это не моя цель. Моя цель сейчас — написать метод. И я на нем фокусируюсь и проверяю только его поведение.
Дальше следующий метод и т.д. А потом в конце, когда у меня есть набор уже проверенных методов я из них, как из конструктора, составляю более сложное поведение, которое уже и видит пользователь и которое я могу покрыть сценарным тестом.
Т.е. сценарный тест проверяет взаимосвязь методов.
(8)
Я именно это и пытался сделать, видимо не получилось =(
Если представить, что методы — это кирпичи, из которых мы строим дом — процесс взаимодействия пользователя в программе (простите за такие примитивные аналогии, лучше не родилось).
Сценарное тестирование — я проверяю как построен дом, а модульное тестирование — я проверяю кирпичи. Иногда очень здорово знать, что кирпичи, из которых мы строим дом, отличного качества =) И не только здорово, но и удобно, т.к. обратную связь можно получить быстрее.
Наличие модульных тестов, не гарантирует работоспособности процесса. И если наша задача — проверить процесс, то вы абсолютно правы, модульный тест не самый лучший инструмент.
сколько пытаюсь представить — никак не получается.
вот допустим есть WMS. почти вся работа идет через RDP-доступ, обработки для ТСД.
как раз сценарное тестирование вроде бы подошло. Надо проверить ожидаемо ли отрабатывает куча нажатий по кнопочкам исполнителем (в т.ч. с учетом того, что с одного экрана по разным кнопочкам-горячим клавишам можно уйти на другие экраны где аналогично — очень быстро ветвится дерево возможностей). при этом то что видно на экране (в т.ч. и набор долступных горячих клавиш) определяется кучей настроечных параметров. как это все прогнать и оцениить правильно ли сценарий отработал или нет — я вообще не представляю. кроме как сидеть и наблюдать и тормозить если вижу проблему…
Или я неграмотный?
(14)
Может стоить начать тестировать конкретные сценарии, а не просто сразу все возможные переходы и ветвления?
Например сценарий «Приемка товара», «Подбор товара», «Отгрузка товара» и т.д.
Каждый сценарий будет:
1. Показывать как ДОЛЖЕН работать функционал — можно также использовать как инструкцию для пользователей
2. Проверять что правильный путь сценария отрабатывает корректно
(15) ну да, только сам по себе сценарий «приемка товара» — достаточно развесистый. реально достаточно развесистый. и как быть? — дробить на суб-сценарии? где каждый субсценарий — это, например, одна включенная галочка в настройках? и как это вообще автоматом тестировать? автоматом включать-выключать настроечные галки и прогонять автоматом сценарий? как знать — правильно отработал сценарий или нет? вручную описывать сценарий (что само по себе уже является ручным прогоном этого сценария) для каждого набора настроечных параметров? ничего непонятно…
(15) сейчас по сути — выставляются конкретные настройки для какого-то одного варианта. и прогоняется сценарий вручную только для этих выставленных настроек.
(17)
Автотест будет делать тоже самое. Только не в ручную проганяться будет, а автоматически. Можно распараллелить запуск тестов, запускать одновременно сразу несколько сценариев
(18) но по-любому, один раз сценарий надо прогнать вручную? и записать его? по всем возможным ветвлениям сценария?
(19) Да, и даже не один.
Сценарий еще отладить нужно
(19) Сергей, тебе уже несколько лет рассказывается и даже показывается, что тесты вполне реально можно сделать.
А ты все «нереально» 🙁
начни с малого — хотя бы один сценарий преврати в тест 🙂
Все возможные ветвления не нужно проверять.
всегда компромисс и приоритезация тест.сценариев по разным критериям — бизнес-польза, частота срабатывания, легкость реализации и т.п.
(22) а сколько времени с нуля для неграмотного занимает развертывание «инфраструктуры» для работы с тестами-сценариями? (все на win-инфраструктуре)
(24)
А вы уверены, что вам нужна инфраструктура?
По началу тесты можно и в ручную запускать. Запуск — 5 мин.
(25) и что — нажимания кнопочек и ввод значений будут сами по себе в тесте выполняться?
(26)
Да, а вы чем-то другим в это время заниматься будете, более полезным