Statement testing что это
statement testing
Смотреть что такое «statement testing» в других словарях:
Statement veracity analysis — There are three principal disciplines of Statement Veracity Analysis.1) Criteria Based Content Analysis ( CBCA)2) Statement Content Analysis ( SCAN ) ª3) Scientific Content Analysis ( SCAN )The study of Statement Analysis is the study of Verbal… … Wikipedia
Software performance testing — In software engineering, performance testing is testing that is performed, to determine how fast some aspect of a system performs under a particular workload. It can also serve to validate and verify other quality attributes of the system, such… … Wikipedia
Regression testing — is any type of software testing which seeks to uncover software regressions. Such regressions occur whenever software functionality that was previously working correctly stops working as intended. Typically regressions occur as an unintended… … Wikipedia
Animal testing regulations — vary around the world. Most governments aim to control the number of times individual animals may be used; the overall numbers used; and the degree of pain that may be inflicted without anaesthetic.EuropeExperiments on vertebrate animals in the… … Wikipedia
psychological testing — Use of tests to measure skill, knowledge, intelligence, capacities, or aptitudes and to make predictions about performance. Best known is the IQ test; other tests include achievement tests designed to evaluate a student s grade or performance… … Universalium
Ian Thorpe and drug testing — The Australian freestyle swimmer Ian Thorpe throughout his competitive career has long been the target of criticism that his exploits have been fuelled by use of performancing enhancing steroids. He has also been a prominent critic of the drug… … Wikipedia
Animal testing — A white Wistar lab rat Description Around 50–100 million vertebrate animals are used in experiments annually. Subjects Animal testing, scien … Wikipedia
Unit testing — In computer programming, unit testing is a method by which individual units of source code are tested to determine if they are fit for use. A unit is the smallest testable part of an application. In procedural programming a unit may be an… … Wikipedia
Genetic testing — (also called DNA based tests) is among the newest and most sophisticated of techniques[1] used to test for genetic disorders which involves direct examination of the DNA molecule itself. Other genetic tests include biochemical tests for such gene … Wikipedia
Statistical hypothesis testing — This article is about frequentist hypothesis testing which is taught in introductory statistics. For Bayesian hypothesis testing, see Bayesian inference. A statistical hypothesis test is a method of making decisions using data, whether from a… … Wikipedia
Модульные тесты в ABAP. Часть третья. Всяческая суета
Эта статья ориентирована на ABAP-разработчиков в системах SAP ERP. Она содержит много специфических для платформы моментов, которые малоинтересны или даже спорны для разработчиков, использующих другие платформы.
Будем меряться
Считается, что главной метрикой качества тестов является покрытие. В разработческих интернетах часто можно встретить формулировки в стиле “полное покрытие”. Как правило, под полным покрытием понимается некий абсолют в 100.00%.
Процент покрытия – цифра сомнительная, ровно настолько же сомнительная, как и “средняя температура по больнице”. Процент покрытия по проекту – это среднее покрытие его частей. То есть: Модуль-1 имеет покрытие 80%, Модуль-2 имеет покрытие 20%, в среднем покрытие будет равно 50%, если допустить что модули примерно равны по содержимому. А верно ли что 80% в четыре раза лучше чем 20%?
Среднее бывает разное. В ABAP UNIT есть три различные метрики покрытия:
NB. Пул подпрограмм проще для демонстрации, чем группа функций или класс с методами. Пул подпрограмм описывается существенно меньшим количеством букв, чем класс. Параметры вынесены за рамки определений. В рамках этой маленькой демонстрации существенной разницы нет. И вообще: все переменные вымышлены, любые совпадения с продуктивным кодом случайны.
И предположим, что мы написали по одному простому тесту на каждую подпрограмму, функцию, метод. Для всех подпрограмм мы будем использовать значения [A = 7, B = 77].
NB: Пусть пока будет общая инициализация, а проверку результата опустим.
Procedure coverage
Это самый простой случай, можно посчитать на пальцах. Покрытие по процедурам будет 100% = ( 1 + 1 + 1 ) / ( 1 + 1 + 1 ) * 100.
Statement coverage
А если для тех же процедур мы посчитаем количество инструкций?
Каждая процедура содержит разное количество инструкций. Причём при заданных входных параметрах будут вызваны не все инструкции:
Если мы посчитаем метрику по инструкциям, то будет 71% = ( 3 + 5 + 2 ) / ( 3 + 8 + 3 ) * 100.
Рассмотрим работу метрики на DO_SOMETHING_ELSE. Инструменты разработки ABAP могут раскрасить строки исходного кода в соответствии с метрикой:
Наглядно, быстро, понятно. Просто удивительно, даже не ожидал такого от ABAP.
Из этой раскраски становится очевидно, что если бы мы взяли другие исходные параметры, то процент покрытия могу бы быть другим. В случае [A = 77, B = 7]:
При этом становится очевидным, что полного покрытия по данной метрике можно достичь только используя более одного тестового сценария. Например, при двух тестах [A = 77, B = 7] и [A = 7, B = 7777] всё позеленеет:
Таким образом метрика выходит на 100%. Можно ненадолго успокоиться.
Branch coverage
Эта метрика работает несколько сложнее. Она берёт все инструкции, которые могут вызвать ветвление, и проверяет их на то, что каждая такая инструкция выполняется в обе стороны.
Посмотрим на базе последнего примера:
Первая инструкция [IF A > B] на двух тестах отработала два раза: один раз по TRUE [A = 77, B = 7] и один раз по FALSE [A = 7, B = 7777].
А вот вторая инструкция [IF D > 1000] отработала только один раз на TRUE [A = 7, B = 7777].
Сам вызов функции считается за безусловную единицу, плюс первый IF даёт два из двух, второй IF даёт только единицу из двух. Значит наша метрика будет равна 80% = (1 + 2 + 1 ) / (1 + 2 + 2) * 100.
И тут уже выходит что для одной функции двух тестов уже мало, а нужно три. К предыдущим двум можно ещё добавить сценарий [A = 7, B = 77], чтобы второй IF отработал на FALSE.
После добавления третьего сценария метрика по этой функции вышла на 100%.
А что же с DO_NOTHING, спросите вы? Не существует такого теста, чтобы метрика по ветвям или инструкциям вышла на 100%. Очевидно, что функция требует рефакторинга, без которого выйти на полное покрытие не получится. Эту функцию следует или удалить, или она должна превратиться из DO_NOTHING в DO_SOMETHING_COMPLETELY_DIFFERENT.
Сто процентов!
Жаль нельзя написать ещё больше тестов и получить более 100%.
Понятно, что метрика Procedure coverage менее показательна в деталях. К ней можно внимательно присматриваться только на ранних этапах, если кода много а тестов ещё почти нет. А вот к какой метрике из двух оставшихся приглядываться после? Если первая метрика просто показывает насколько широко вы охватили функционал, то последние показывают, насколько вы его качественно охватили.
Как вы заметили, можно получить 100% по инструкциям, но при этом не будет 100% по ветвям. Но не наоборот (или я не могу придумать такой пример). Если вы уж получили 100% по ветвям, то значит вы зашли во все закоулки и все инструкции отработали. Но кому-то может показаться, что метрика по ветвям даёт менее показательные весовые коэффициенты в среднем, так как игнорирует один из явных весовых показателей – количество строк кода, то есть количество инструкций.
BTW: Да, пустая процедура даёт 100% показатели!
Уговор есть уговор
Для работы ABAP Unit неважно:
Следовательно, у нас по каждому пункту должна быть некоторая общая условная договорённость, облегчающая общее восприятие картины. Вроде соглашения по именованию или форматированию.
Тестовых классов должно быть ровно столько сколько нужно. Как минимум, каждый большой объект (группа функций, программа, класс) должен иметь один тестовый класс, можно больше.
Если у вас простая группа из нескольких связанных функций, то к ней достаточно и одного класса. А вот если в вашей группе есть шесть пачек малосвязанных функций, то здесь здесь должен скорее возникнуть вопрос “А сколько должно быть групп функций?”, а это тема для совсем другого разговора.
После корректного ответа на данный вопрос можно взять метод SETUP в качестве критерия делимости. Такой метод в классе должен быть один, вызывается он автоматически перед каждым тестовым методом.
Каждый сценарий должен дать отдельный тестовый метод, наименование метода должно прямо выводиться из тестируемого кода.
Один из принципов модульного тестирования: тестовый класс должен тестировать только тот код, в юрисдикции которого он находится. И хотя тесты могут находиться в любом месте исходного кода, но стоит отделять работающую функциональность от тестов.
Вот мастер для групп функций создаёт отдельную include-программу по предопределённому шаблону: например: LZFI_BTET99 для группы функций ZFI_BTE. Ничего плохого в этом не вижу, надо принимать за образец и продолжать в том же духе.
Также и в программах типа REPORT: пишите тесты строго в одной отдельной include-программе, с именем по шаблону.
Впрочем, никому не могу запретить писать всё вперемешку: код, его тест, код, его тест…
Когда?
Нельзя каждые пять минут запускать полный цикл модульных тестов. Но, как минимум, перед деблокированием запроса необходимо запускать тест причастных объектов.
Подытожу
Просто пачка тезисов для подведения черты:
Прямая реальная польза от тестов будет только в те моменты, когда по прошествии времени тесты будут провалены, когда кто-то будет допиливать эту функциональность.
Потому что умение правильно падать – самый лучший способ избежать травм. Если это верно для каратистов и велосипедистов, значит и для программистов тоже будет нелишним. Лучше правильно упасть плохо крутя педали, чем неправильно упасть хорошо крутя педали. Умение правильно падать важнее правильной экипировки.
А прямо сейчас можно извлечь только косвенную пользу:
Основные определения и понятия тестирования ПО
Чтобы с головой погрузиться в новую профессиональную область, важно изучить язык, на котором говорят её представители. Ведь специальная лексика не только описывает инструменты или процессы, с которыми тестировщики работают ежедневно, но и облегчает общение с коллегами на около рабочие темы.
К примеру, вы уже могли слышать фразу «это не баг, а фича». Объяснить её далёкому от информационных технологий собеседнику не так просто: в отличие от бага, который является ошибкой, фича ― это не дефект, а заранее и сознательно придуманная опция, которая служит изюминкой. Слишком долго, не так ли?
Использование подобных словечек поможет вам проявить свои знания на собеседовании и найти общий язык с HR, уже работающим в ИТ-индустрии человеком. Итак, какие же понятия и определения будут полезны каждому начинающему QA-специалисту?
Базовые термины
Баг (bug) ― это ошибка или дефект программного обеспечения. Он проявляется, когда фактическое поведение системы отличается от ожидаемого. Дефекты могут быть критическими и влиять на использование ПО или незначительными, когда их присутствие незаметно для пользователя.
Тестирование (testing) ― это исследование поведения программного продукта, основной целью которого является выявление багов. Понятия контроль качества (quality control, QC) и обеспечение качества (quality assurance, QA) часто используются в качестве синонимов, но это ошибка. Ведь тестирование нацелено на поиск ошибок в уже готовом ПО, а обеспечение качества задаёт условия, в которых дефекты появляться не будут.
Подробно об отличиях данных явлений мы рассказали в нашей статье.
Тестовое покрытие (test coverage) ― это совокупность тестов, которые проявляют работоспособность той или иной функциональности ПО. Чем больше проверок, тем шире тестовое покрытие, тем больше возможностей отследить поведение системы в различных условиях и выявить критические или незначительные дефекты.
Верификация (verification) ― оценка ПО или его компонентов с точки зрения соответствия всем заявленным к нему требованиям.
Валидация (validation) ― это проверка работоспособности функциональности приложения.
Релиз (release, RTM) ― выпуск программного продукта на рынок, например, размещение мобильного приложения в App Store или Google Play.
Артефакты ― это документы, которые используют в процессе тестирования. Подробнее о том, какими они бывают, расскажем далее.
Артефакты
Спецификация (specification, спек) ― детализированное описание работы приложения, которое включает технические свойства.
Баг-репорт (bug report, отчёт об ошибке) ― описание действий или условий, которые привели к выявлению дефекта. О принципах составления безупречного баг-репорта мы уже рассказали в одной из наших статей.
Подобные отчёты создают в баг-трекинговой системе (bug tracking system, система отслеживания ошибок). Это программа для описания и контроля дефектов. Наиболее распространённой является Jira. Новичку привыкнуть к работе в этой системе непросто, но освоить азы вы сможете с поддержкой опытного преподавателя-практика на базовом курсе от QA Academy.
План тестирования (test plan) ― в этом документе содержатся все данные о проводимой проверке: описание программного продукта, стратегия тестирования, сроки выполнения поставленных задач, используемые в процессе инструменты и оборудование, оценка потенциальных рисков и прочее.
Чек-лист (checklist, контрольный список) ― перечень параметров, которые нуждаются в проверке.
Тест-кейс (test case, тестовый случай) ― своего рода сценарий или описание последовательности шагов при проведении тестирования.
Тестовый набор (test suite) ― несколько тест-кейсов, которые объединены по типу тестирования или другим признакам.
Типы тестирования
Мануальное (ручное) ― непосредственная проверка работы ПО тестировщиком.
Автоматизированное ― оценка качества программного продукта с применением программных средств (автотесты).
Тестирование производительности (performance testing) ― анализ работы приложений под различными нагрузками.
Функциональное тестирование (functional testing) ― проверка возможности ПО в заданных условиях решать необходимые пользователю задачи.
Тестирование безопасности (security testing) ― определение безопасности ПО: защищено ли оно от атак хакеров, несанкционированного доступа к данным и т. д.
UX-тестирование (usability testing, юзабилити-тестирование) ― исследование логики и удобства использования ПО.
Подробнее о различных подходах оценки качества ПО вы узнаете из нашего материала по классификации видов тестирования.
Ещё несколько полезных слов
Фиксить (от англ. to fix — исправлять) — вносить правки, исправлять ошибки.
Локаль (от англ. locale — место) — региональные настройки или параметры ПО.
Билд (от англ. to build — строить) — финальный вариант программного продукта или его элемента, который готов к тестированию.
Асайнить (от англ. to assign — назначать) — закреплять за кем-то задачу или часть работы.
В аттаче (от англ. to attach — приложить) — добавлять к письму или сообщению документ. Например, отправить на почту письмо с CV в аттаче означает, что было отправлено письмо с приложенным к нему резюме.
Букать (от англ. to book — бронировать) — резервировать.
Бэкапить (от англ. backup — дублирование) — создавать резервные копии документов или данных на случай их потери или удаления.
Дебаджить, дебажить (от англ. to debug — отлаживать) — настраивать или регулировать работу.
Тул (от англ. tool — инструмент) — программа, которая используется при тестировании.
Фича (от англ. feature — особенность) — некий аспект ПО, который служит его характерной особенностью.
Резюмируем
Мы постарались собрать самые важные слова и понятия, которые будут полезны на старте карьеры в QA. Они облегчат понимание профильной литературы и общение с коллегами. Поможет обогатить лексику регулярное чтение статей про тестирование, тематические блоги и литература.
Но быстрее всего пополнить словарик вы сможете в процессе живого общения во время рабочего процесса. Чтобы уже через несколько месяцев вы смогли реализоваться в QA, записывайтесь на курсы Академии сегодня!
Белый ящик Пандоры
Обсуждая тестирование, чаще всего спикеры говорят об особенностях подхода, известного как «черный ящик». Но здесь мы поговорим о противоположном сценарии — «белом ящике», позволяющем формулировать вопросы к коду, понимая его внутреннюю структуру.
В основе статьи — расшифровка доклада Никиты Макарова (Одноклассники) с нашей декабрьской конференции Heisenbug 2017 Moscow.
Теория
На большом количестве конференций и в очень большом количестве книг, блог-постов и прочих источников говорится о том, что тестирование методом черного ящика — это хорошо и правильно, потому что именно так пользователь видит систему.
Мы как бы присоединяемся к нему — видим и тестируем ее так же.
Это все классно, но почему-то очень мало говорится про белый ящик.
Однажды мне и самому стало интересно, почему так. Что такое тестирование белого ящика?
Определение белого ящика
Я полез разбираться. Начал искать источники. Качество русскоязычных оказалось очень низким, переведенных с английского на русский — чуть выше. И я добрался до англоязычных источников — до самого Гленфорда Майерса (G. Myers), который написал замечательную книгу «The Art of Software Testing».
Буквально во второй главе автор начинает говорить про тестирование белого ящика:
«To combat the challenges associated with testing economics, you should establish some strategies before beginning. Two of the most prevalent strategies include black-box testing and white-box testing…»
В конце в словаре Майерс дает некое определение тестированию белого ящика:
«White-box testing — A type of testing in which you examine the internal structure of a program».
Что же на практике? Майерс предлагает строить тестовые сценарии, ориентируясь на покрытие:
Что сейчас нужно понимать под тестированием белого ящика? Мы смотрим в код, понимаем структуру и зависимости, которые есть в этом коде, задаем вопросы, делаем выводы и проектируем тесты на основе этих данных. Мы выполняем эти тесты вручную или автоматически и на их основе получаем новые данные о состоянии нашей системы — о том, как она может или не может работать. Это и есть наш профит.
Зачем нужен белый ящик?
Зачем нам всем этим заниматься, если у нас есть черный ящик — то есть то, как пользователь видит систему? Ответ очень простой: жизнь сложна.
Это стек вызовов обычного современного энтерпрайзного приложения, написанного на языке Java:
Не только на Java все так многословно и обильно. На любом другом языке это будет выглядеть примерно так же. Что здесь есть?
Здесь есть вызовы веб-сервера; security framework-а, который делает авторизацию, аутентификацию, проверяет права и все остальное. Здесь есть web-фреймворк и еще один web-фреймворк (потому что в 2017 году нельзя просто так взять и написать энтерпрайзное приложение на одном web-фреймворке). Здесь есть фреймворки для работы с базой данных и преобразования объектов в столбцы, таблицы, колонки и все остальное. И здесь есть маленький желтый квадратик — это один вызов бизнес-логики. Все, что под и над ним, происходит в вашем приложении каждый раз.
Пытаясь подобраться к этой штуке где-то снаружи с черным ящиком (как это видит пользователь), вы очень много чего можете не протестировать. А иногда вам это очень надо, особенно когда поведение пользователей меняет что-то в security, пользователя перенаправляют в какие-то другие места или что-то происходит в базе данных. Черный ящик не позволяет вам этого сделать. Именно поэтому нужно залезать внутрь — в белый ящик.
Как это делать? Давайте посмотрим на практике.
Практика
Чтобы не было неправильных или завышенных ожиданий, давайте с самого начала проясним некоторые детали:
Easy level
Как я говорил, мы смотрим в код и видим:
Я не хочу долго здесь задерживаться. Про это есть куча интересных докладов.
Medium level
Средний уровень сложности отличается масштабом. Когда вы работаете в маленькой компании или команде, вы единственный тестировщик, у вас есть три-четыре разработчика (как и в среднем по отрасли), 100 тыс. строк кода на всех, а код-ревью осуществляется метанием тапка ведущего разработчика в того, кто провинился, — какие-то специальные инструменты вам не нужны. Но так бывает редко.
Большие успешные проекты обычно «размазаны» на несколько офисов и команд разработки. А размер кодовой базы начинается с миллиона строк кода.
Когда в проекте очень много кода, разработчики начинают выстраивать формальные правила, по которым пишется этот код:
Давайте посмотрим на примере.
ArchUnit
ArchUnit позволяет в виде более-менее проблемно-ориентированного языка описывать формальные правила того, что должно или не должно быть в коде, и запихивать их в виде стандартов unit-тестов внутрь каждого проекта. Так изнутри проекта ArchUnit позволяет проверять, что в нем соблюдается «санитарный минимум».
Итак, у нас есть правило ArchRuleDefenition :
Давайте запустим этот тест. Он замечательно падает:
При этом он пишет, что у нас нарушено правило (когда класс, находящийся в таком-то пакете, стучится в классы, которые находятся в другом пакете). Что более ценно, в виде стек-трейса он показывает все строчки, где это правило не соблюдается.
ArchUnit — замечательный инструмент, который позволяет встраивать подобные штуки в CI/CD цикл, то есть писать внутри проекта тесты, которые проверяют какие-то архитектурные правила. Но у него есть один недостаток: он проверяет все тогда, когда код уже написан и куда-то закоммитчен (то есть сработает либо commit hook, который отклонит этот коммит, либо еще что-то). А бывают ситуации, когда нужно, чтобы плохой код вообще нельзя было написать.
Annotation Processing
Исходный код примера:
На самом деле кодогенерация может решить много проблем. Она позволяет не только создавать код, который не хочется писать, но и запрещать создание кода, который не должен быть написан. Давайте посмотрим, как это работает.
Большая часть кодогенерации работает на процессинге аннотаций. У меня есть проект, где описана пара процессоров аннотаций, которые специфичны для мира Java-разработки, — в частности, аннотация Pojo. В программах на Java нет такого понятия как структуры. Отцы-основатели Java сейчас думают о том, чтобы ввести структуры в язык программирования. В Cи это уже было, у нас — еще нет (хотя прошло больше 40 лет). Но мы смогли выкрутиться — у нас есть Pojo (plain old java object), то есть объекты с полями, геттерами, сеттерами, но в них больше ничего нет — никакой логики.
У меня есть аннотация, которая характеризует собой объект Pojo, а также аннотация, которая характеризует собой Helper — это объект без состояния, в который напиханы всякие методы процедурного рода (чистая бизнес-логика). И у меня есть два процессора таких аннотаций.
Процессор аннотаций Pojo ищет в коде соответствующие аннотации, а когда находит, проверяет код на соответствие тому, что является (или не является) Pojo. Аналогично действует процессор аннотаций Helper (вот ссылка на аннотации и процессоры аннотаций).
Как это все работает? У меня есть маленький проект, я запускаю в нем компиляцию:
Я вижу, что оно даже не компилируется:
Это происходит потому, что в этом проекте содержится код, который нарушает правила:
В отличие от предыдущего примера, эта штука встраивается внутрь среды разработки, внутрь continuous integration, то есть позволяет охватывать больший контур внутри CI/CD-цикла.
Nightmare level
Когда вы наигрались на предыдущих уровнях, вам хочется чего-то большего.
Покрытие кода
Для измерения покрытия кода, с тех пор, как Майерс написал свою книжку, появилось очень много разных инструментов. Они есть практически для каждого языка программирования. Здесь я привел только то, что я посчитал популярным по количеству ссылок на них в интернете (вы можете сказать, что это неправильно — я с вами соглашусь):
Инструменты есть и, более того, существует интеграция этих инструментов со средами разработки, когда мы видим эту замечательную штучку слева, свидетельствующую о том, что этот кусок кода покрыт unit-тестами (зеленый цвет), а этот — нет (красный цвет).
И глядя на это в контексте unit-тестов, хочется задать вопрос — почему так нельзя сделать с интеграционными или с функциональными тестами? Где-то можно!
Но кроме тестов у нас есть пользователи. Тестировать можем все, что угодно (главное тестировать не фигню), но пользователи давят в какое-то одно место, потому что они этим пользуются 95% времени. И почему нельзя сделать такие же красивые полосочки, но только для кода, который используется или не используется?
На самом деле, так сделать можно. Давайте посмотрим, как.
Представьте, что я тестировщик этого приложения. И мне оно попадает на регрессионное тестирование («Срочно, горим, делаем мега-стартап, надо проверить, что работает, что не работает»). Я провожу с ним все эти манипуляции — все работает, мы отпускаем в релиз. Релиз проходит успешно, все хорошо.
Проходит полгода — ситуация повторяется. За полгода разработчики что-то там поменяли. Что именно, я не знаю. Могу ли я это узнать — это отдельный вопрос. Но самое главное — какой код теперь вызывается? Все ли я проверил нажатием одной единственной кнопки или не все? Понятно, что не все, но не пропустил ли я чего-то важного?
На эти вопросы можно найти ответы, если вместе с приложением запустить агент, снимающий с него покрытие.
Я использовал Jacoco. Можно брать любой, главное, чтобы вы потом могли понять, что он вам намерял. В результате работы агента у нас появился файлик jacoco.exec:
Из этого файлика, исходного приложения и бинарника приложения можно создать отчет, из которого будет видно, как это все работает.
У меня есть маленький скрипт, который проанализировал эту штуку и создал папку html:
Скрипт показывает вот такой отчет:
В процессе тестирования я что-то продавил руками, а что-то нет — в разном процентном соотношении. Но так как мы не стесняемся заглядывать в белый ящик и смотреть, что же происходит внутри приложения, мы знаем, куда нам нужно давить.
В этом отчете зеленым подсвечиваются те строчки, которые я «продавил». Красным — которые не продавил.
Если мы прочтем этот код более-менее вдумчиво (даже не вникая в то, что происходит внутри), мы сможем понять, что никакую работу, связанную с отказом сети, я не продавил. Также я не проверил кейсы получения нехорошего статус-кода (что мы не авторизованы запрашивать репозитории этой организации).
Для проверки падения сети можно обрушить сетку или внедрить Fault Injection testing, а можно написать другой Fault Injection implementation, положив ее в каталог с приложением, получать статус-код не 200, а, например, 401.
Пытаясь ответить на вопросы о том, что проверяется нашими тестами, куда давят наши пользователи и как на самом деле одно соотносится с другим, мы в Одноклассниках создали сервис, который умеет сводить все воедино. Мы же делаем пользовательский сервис. Мы можем тестировать какой-то забытый уголок нашего большого портала, куда никто не заходит, но какая в этом ценность?
Сначала мы назвали его Cover. Но потом из-за опечатки одного из наших инженеров мы переименовали его в KOVЁR.
KOVЁR знает о нашем цикле разработки ПО, в частности, когда нужно включить замер покрытия, когда нужно его выключить, когда с этого надо срендерить отчеты. И KOVЁR позволяет нам сравнивать отчеты по тому, что было, допустим, на прошлой неделе, и на этой; по тому, что мы сделали автотестами, и тому, что продавили люди руками.
Выглядит это так (это реальные скриншоты с KOVЁR):
Получаем side-by-side сравнение одного и того же кода. Слева находятся автотесты, справа — пользователи. Красным подсвечено то, что не продавлено, зеленым то, что продавлено (в данном случае автотесты продавливают конкретный кусок бизнес-логики намного лучше, чем пользователи).
Как вы понимаете, все может корректироваться: лево и право могут меняться, используемые цвета — тоже.
В итоге получаем такую довольно простую матрицу 2х2, характеризующую код:
Там, где у нас есть покрытие и автотестами, и людьми — его нужно сравнивать, и с этим KOVЁR работает. Где есть покрытие автотестами, но нет людей, надо хорошо подумать. С одной стороны, это может быть мертвый код — очень большая проблема современной разработки. С другой — это может быть функционал, который используется людьми в каких-то экстренных обстоятельствах (восстановление пользователей, разблокировка, бэкап, восстановление из бэкапа — то, что вызывается крайне редко).
Там, где нет автотестов, но есть люди, очевидно, надо писать код, покрывая эти места, и стремиться к разумному, доброму, вечному. А где нет ни автотестов, ни людей — в первую очередь нужно вставить какие-то метрики и проверить, что этот код действительно никогда не вызывается. После этого надо безжалостно его удалить.
Инструменты Code Coverage уже существуют, и надо их просто интегрировать к себе. С ними вы сможете:
Метаинформация
Существует классическая математическая задачка о компоновке рюкзака: как упаковать все вещи в рюкзак, чтобы они туда поместились и осталось как можно больше пространства. Я думаю, многие из вас слышали про нее. Давайте посмотрим на нее в контексте тестирования.
Предположим, у меня есть 10 автотестов. Они выглядят так:
В реальности каждый автотест бегает разное время. Поэтому в определенный момент времени они выглядят вот так:
И у нас есть два ресурса, на которых мы их запускаем:
Если мы возьмем эти 10 тестов и раскинем их на два ресурса поровну, получим такую картину:
Эта картинка — не хорошая и не плохая, но в ней есть одна особенность: первый ресурс у нас достаточно долгое время простаивает, а тестирование на втором ресурсе еще идет.
Не меняя количество тестов на каждом из этих ресурсов, можно просто перегруппировать их и получить вот такую картинку:
В каждом ресурсе осталось по пять тестов, но простой сократился — мы сэкономили примерно 20% времени тестирования. Когда мы первый раз врубили у себя эту оптимизацию, она реально сэкономила нам 20%. То есть эта цифра не с потолка, а из практики.
Если рассматривать эту закономерность дальше, то скорость тестов — это всегда функция от того, сколько у вас есть ресурсов и сколько у вас есть тестов. Дальше вы должны ее балансировать и как-то оптимизировать.
Потому что не все всегда одинаково. Предположим, к вам кто-то прибегает на ваш Continuous integration server и говорит, что нам нужно срочно запустить тесты — проверить фикс и сделать это как можно быстрее.
Вы можете пойти на поводу у этого человека и дать ему все возможные ресурсы для запуска тестов.
Правда может оказаться в том, что их фикс не очень важен по сравнению с текущим релизом, который должен выкатываться через два часа. Это первое.
А второе — тестов на самом деле не так много, как у вас ресурсов. То есть картинка, которую я показал раньше, где у вас 10 тестов и два ресурса, — это очень большое упрощение. Ресурсов может быть 200, а тестов — 10 тыс. И эта игра с тем, сколько кому дать ресурсов, начинает влиять на всех.
Чтобы правильно играть в эту игру, нужно всегда иметь ответы на два вопроса: сколько у вас ресурсов для запуска и сколько тестов.
Если вы будете достаточно долго думать над вопросом о том, сколько у вас ресурсов и сколько у вас тестов (особенно над последним), рано или поздно вы придете к мысли о том, что было бы неплохо парсить код ваших тестов и разбираться в том, что же в нем происходит:
Вам эта мысль может показаться безумной, но не гоните ее сразу. Все среды разработки уже делают это, чтобы показывать вам вот такие подсказки:
Причем они занимаются парсингом не только кода, но и всех зависимостей в нем.
Они умеют это делать. Более того, все среды разработки делают это хорошо, а некоторые даже поставляют библиотеки, которые позволяют решать такие задачи буквально в шесть строчек (по крайней мере, для Java).
В этих шести строках вы разбираете и полностью парсите какой-то кусок кода. Вы можете достать из него любую метаинформацию: сколько в нем полей, методов, конструкторов — чего угодно, в том числе тестов.
И имея все это в голове, мы создали сервис, который называется Berrimor.
BERRIMOR умеет говорить «овсянка, сэр!», а еще он умеет:
Я мог бы показать вам интерфейс BERRIMOR, но вы бы все равно ничего там равно бы. Вся его мощь кроется внутри API.
Социальный анализ кода
В 2010 году я читал лекции Сергея Архипенко по управлению программными проектами и мне запомнилась вот эта вот цитата:
«…реальность, которая заключена в особой специфике производства программ, по сравнению с любой другой производственной деятельностью, потому что то, что производят программисты – нематериально, это коллективные ментальные модели, записанные на языке программирования» (Сергей Архипенков, Лекции по управлению программными проектами, 2009).
Ключевое слово — коллективные. У людей есть почерк, но не у всех он хороший. У программистов тоже есть почерк (и также не всегда хороший). Между людьми существуют какие-то взаимосвязи: кто-то пишет фичу, кто-то ее патчит, кто-то ее чинит. Эти зависимости есть внутри каждого коллектива, внутри каждой команды разработки. И они влияют на качество того, что происходит в проекте.
Социальный анализ кода — нарождающаяся дисциплина. Я выделил три видео, которые есть в открытом доступе и могут помочь вам понять, что же это такое.
Социальный анализ кода позволяет:
Когда я что-то пишу и коммитчу, я указываю ссылку на тикет в Jira. В силу NDA я не могу показывать вам социальный анализ кода на примере репозиториев «Одноклассников». Я покажу на примере open source-проекта Kafka.
Итак, у меня есть (маленькое утилитное приложение), которое поднимает все коммиты в этом репозитории и разбирает все комментарии к ним, обеспечивая поиск по регулярному выражению Pattern.compile(«KAFKA-\\d+») коммитов, которые ссылаются на какой-то тикет.
В консоли видно, что коммитов всего 4246, а коммитов без такого упоминания — 1562. То есть точность анализа на треть меньше, чем хотелось бы.
Дальше мы поднимаем каждый коммит, составляем из него индекс — какие файлы в нем менялись (под какой тикет). Составляем все эти индексы в большой хэшмап: имя файла — список тикетов, по которым этот файл менялся. Вот как это выглядит:
Например, у нас есть файл KafkaApis и рядом огромный список issue, по которым он менялся (API меняется часто).
итоге мы получаем вот такой вывод:
Где мы пишем, какой процент изменений был в том или ином файле:
Например, для верхней строки общее количество тикетов, которые прошло в коммитах через этот файл, — 231, из них багов — 128 и, соответственно, 128 делим на 231 — получаем 55% — доля изменений. С большой вероятностью технический долг сосредоточен именно в этих файлах.
Итоги
Я вам показал шесть разных примеров. Это далеко не все, что существует. Но это значит, что белый ящик — это в первую очередь стратегия. Как вы ее будете реализовывать на вашем проекте — вам виднее. Надо думать, не надо бояться залезть в код. Там всегда лежит вся правда о вашем проекте. Поэтому читайте код, пишите код, вмешивайтесь в тот код, который пишут программисты.
Если тема тестирования и обработки ошибок вам так же близка, как и нам, наверняка вас заинтересуют вот эти доклады на нашей майской конференции Heisenbug 2018 Piter: