Quality Gates
Quality Gates — это набор условий, которым должен соответствовать проект, прежде чем он сможет претендовать на релиз. Концепция Quality Gates возникла еще в 1986 году и изначально применялась для контроля качества в автомобильной промышленности. Это лучший способ обеспечить соблюдение всех стандартов и их регулирование на проекте. Quality Gates можно определить как набор пороговых показателей, таких как Code Coverage, технический долг, количество блокирующих проблем и уязвимостей, дубликаты кода и т.д.
Linters
Проверка кода линтерами помогает избежать многих ошибок еще на этапе написания кода. Анализ синтаксиса и структуры кода проводится автоматически и при обнаружении нарушений правил написания кода, выводится соответствующее сообщение в консоль. Такой подход позволяет избежать очень много типовых ошибок на ранних этапах разработки, а так же значительно сэкономить время и силы на код-ревью.
Первый линтер был написан Стивеном Джонсоном в 1978 году, когда он работал в операционной системе Unix в Bell Labs. После появилось много других линтеров на разные языки программирования с различными настройками, позволяющие статически анализировать код, используя настройки конфигурации и проверяя соответствие кода заданным проектным требованиям по стилю и правилам безопасности.
Основные задачи линтеров:
1. Статический анализ — автоматизированное программное обеспечение проходится по Вашему коду (не выполняя его) и тем самым статически проверяет на наличие ошибок, например, табуляция, нейминг, утечки памяти, соответствие правилам Code standards, которые приняты на проекте и многое другое.
Code standards — это набор правил и соглашений, используемых при написании исходного кода на определенном проекте. Это обеспечивает читаемость кода, сохраняет одинаковую стилизацию по всему проекту и ускоряет процесс адаптации новых сотрудников.
2. Проблемы с безопасностью — есть специальные плагины, например eslint-plugin-security
для node js, которые позволяют выявить слабые места безопасности, например, использование команды eval, вызов дочерних процессов, импорт модулей с передачей в соответствующую команду чего-то, отличающегося от строкового литерала и т.д.
3. Улучшения производительности — есть несколько правил по написанию кода, которые позволят улучшить производительность, например в CSS — селектор * или слишком длинная цепочка селекторов
#header .header__inner nav ul.nav-menu li:hover a {}
могут ухудшить скорость загрузки страницы.
4. Упрощения процесса Code review — поскольку описки и другие банальные ошибки будут исправлены до процесса Code review, во время просмотра Pull Request не будет необходимости тратить время на проверку синтаксиса кода и соответствие его базовым кодовым стандартам, а можно будет сосредоточиться на анализе выбранного решения, что значительно сэкономит время всех участников процесса review.
5. Делает код читаемым. Если стиль написания кода не изменяется от файла к файлу и в различных функциях — это делает код читаемым и легким для восприятия.
Рассмотрим пример такого кода:
function sayHello(name){
alert("Hello " + name);
}
name = "Albus Dumbledore";
sayHello(name)
После проверки линтерами вы увидите следующие ошибки:
Ожидается пробел между ‘)’ и ‘{‘
function sayHello(name){
Ожидается ‘use strict’ перед ‘alert’.
alert("Hello " + name);
Необъявленная переменная ‘name’
name = "Albus Dumbledore";
Необъявленная переменная ‘name’
sayHello(name)
Ожидается ‘;’ в конце строки
sayHello(name)
Pre-commit
Для уверенности в том, что все синтаксические ошибки исправлены на максимально раннем этапе — рекомендуют запускать линтеры в обязательном порядке перед каждым коммитом. В таком случае пока все ошибки не будут исправлены — система не позволит Вам сделать коммит в репозиторий.
Для создания Pre-commit хука установим пакет husky и включим хук в package.json
:
{
"husky": {
"hooks": {
"pre-commit": "eslint src --fix"
}
}
}
Также рекомендуется добавление запуска Unit Tests в прекоммит хук, но об этой теме мы поговорим далее.
Code review
Code review — это анализ написанного кода другими разработчиками перед добавлением кода в общую ветку.
Основные задачи процесса Code review:
- Выявить ошибки в коде
- Улучшить качество кода
- Обмен знаниями между членами команды — об измененном функционале
Подготовка к Code review:
- Изменения должны иметь узкую, четко определенную и замкнутую область, которую они полностью охватывают
- Более короткие изменения предпочтительнее более длительных. Если вносятся существенные изменения в более чем ~ 5 файлов, или на созданиe Pull Request уходит более 1-2 дней, или на рассмотрение требуется более 20 минут, можно попробовать разделения PR на несколько автономных.
- Перед созданием PR запустите все линтеры кода и Unit тесты для того, что бы найти самые примитивные и распространенные ошибки.
Анализ кода с помощью SonarQube
SonarQube — это платформа с открытым исходным кодом, предназначенная для непрерывного анализа и измерения качества кода. В SonarQube есть набор правил для анализа исходного кода во время компиляции с целью выявления потенциальных уязвимостей, ошибок, анти-шаблонов и плохих методов кодирования. Также можете создать новые Quality Gates для своих проектов и определять индивидуальные пороговые значения.
При запуске SonarQube он определит, соответствует ли код всем установленным вами порогам качества, в случае если какой-то из Quality Gates нарушен — автоматическая сборка проекта завалится.
Automation Tests
В то время как выполнения тестов вручную — это медленный и кропотливый процесс, автоматическое тестирование позволяет один раз написать тестовые сценарии и автоматически запускать их каждый раз, когда разработчики вносят изменения в код приложения. Инструмент автоматизации тестирования собирает результаты и представляет их в удобном для чтения формате. Это позволяет вашей команде разработчиков своевременно тестировать программное обеспечение на предмет дефектов и быстро их исправлять.
Automation тесты делятся на 3 уровня: Unit tests, Integration и GUI (Graphical User Interface). Пирамида автоматизированного тестирования наглядно показывает сколько тестов какого уровня должно присутствовать. Unit tests — самые быстрые и простые тесты в написании, соответственно и самые дешевые, а это значит, что их должно быть больше всего на проекте. Интеграционные тесты предназначены для проверки связи между компонентами, а также взаимодействия с различными частями системы. GUI тестирование программного обеспечения проверяет графический интерфейс пользователя, а именно то, что при взаимодействии пользователя с приложением, например клик по кнопке или отправлении формы — пользователь получит ожидаемый результат. Эти тесты являются самыми сложными в написании и поддержке, требуют наибольшее время для прохождения, потому их количество должно быть наименьшее, в сравнении с другими тестами. GUI тесты следует запускать уже после того, как убедитесь, что Unit и Integration тесты прошли успешно.
Automation тесты позволяют:
- Снизить затраты на разработку проекта
- Увеличить test coverage
- Повысить точность тестирования
- Увеличить скорость тестирования и разработки проекта
- Быстро обнаружить и и исправлять дефекты
Чем раньше мы выявим проблемы, тем проще и дешевле их решить — используя возможности статического анализа кода, разработчики могут получать раннюю обратную связь об изменениях, находить и выявлять ошибки на самых ранних этапах.
Unit Tests
Unit Tests — это тестирование наименьшей части приложения — отдельной функции в изоляции от внешней логики. Задача каждого отдельного теста проверить, что при попадании на вход функции возвращается ожидаемый результат. Тесты должны быть максимально изолированы от приложения, для чего используются моки данных и функций.
Написание каждого теста проходит в 3 этапа:
- Создание нужных для теста данных
- Вызов тестируемой части кода
- Проверка результатов — сравнивание с ожидаемыми
Для unit-тестирования в Angular приложениях используется фреймворк Jasmine, для запуска тестов в разных браузерах или в headless mode используется Karma.
Структура тестов:
describe('tests group', () => {
beforeEach(() => {...});
it('test description', async(() => {
expect(...).toBe(...);
}));
...
});
Функция describe()
объединяет в себе группу взаимосвязанных тестов, где первый параметр (string) — текстовое описание группы, второй параметр — функция, которая содержит конфигурацию и набор тестов.
Функция it()
описывает каждый тест в отдельности, она принимает 2 параметра — тестовое описание функции и функцию теста.
Функция beforeEach()
используется для того, что бы задать исходное состояние перед каждой функцией it()
.
Функция expect()
служит для проверки результатов, она принимает параметр — результат и позволяет его проверить одним из способов (toBeTruthy, toEqual, toContain …)
Unit тестов всегда наибольшее количество, так как они маленькие, не занимают много времени на написание и поддержку, не требуют много ресурсов и в кратчайшие сроки позволяют разработчикам обнаружить ошибки в коде еще на ранних этапах разработки.
Code Coverage — одна из оценок качества тестирования приложения. Она показывает на сколько хорошо приложение покрыто тестами в процентном соотношении.
Источники: Habr, Medium, Codereadability, Javarush, Samirbehara, Mindk