Это руководство описывает стандарты и лучшие практики для автоматизированного тестирования GitLab CE и EE.
Оно предназначено как расширение руководства по стилю тестирования thoughtbot. Если это руководство определяет правило, которое противоречит руководству thoughtbot, то данное руководство имеет приоритет. Некоторые руководства могут быть повторены дословно, чтобы подчеркнуть их важность.
Формальное определение: https://en.wikipedia.org/wiki/Unit_testing
Эти виды тестов обеспечивают, что отдельная единица кода (метод) работает так, как ожидалось (при входных данных, он имеет предсказуемый выход). Эти тесты должны быть изолированы настолько, насколько это возможно. Например, методы моделей, которые не работают с базой данных, не должны требовать записи базы данных. Классы, которые не требуют записей базы данных, должны использовать подмены/дублирования настолько, насколько это возможно.| Путь к коду | Путь к тестам | Тестовый движок | Примечания |
| --------- | ---------- | -------------- | ----- |
| app/finders/
| spec/finders/
| RSpec | |
| app/helpers/
| spec/helpers/
| RSpec | |
| app/db/{post_,}migrate/
| spec/migrations/
| RSpec | Подробнее в spec/migrations/README.md
. |
| app/policies/
| spec/policies/
| RSpec | |
| app/presenters/
| spec/presenters/
| RSpec | |
| app/routing/
| spec/routing/
| RSpec | |
| app/serializers/
| spec/serializers/
| RSpec | |
| app/services/
| spec/services/
| RSpec | |
| app/tasks/
| spec/tasks/
| RSpec | |
| app/uploaders/
| spec/uploaders/
| RSpec | |
| app/views/
| spec/views/
| RSpec | |
| app/workers/
| spec/workers/
| RSpec | |
| app/assets/javascripts/
| spec/javascripts/
| Karma | Подробнее в разделе JavaScript. |### Интеграционные тесты
Формальное определение: https://en.wikipedia.org/wiki/Integration_testing
Эти виды тестов обеспечивают, что отдельные части приложения работают хорошо вместе, без избыточного окружения приложения (например, браузера). Эти тесты должны утверждать на уровне запроса/ответа: код состояния, заголовки, тело. Они полезны для тестирования прав доступа, переадресаций, какая вьюха отображается и т.д.| Путь к коду | Путь к тестам | Тестовый движок | Примечания |
| ----------- | ------------- | --------------- | ---------- |
| app/controllers/
| spec/controllers/
| RSpec | |
| app/mailers/
| spec/mailers/
| RSpec | |
| lib/api/
| spec/requests/api/
| RSpec | |
| lib/ci/api/
| spec/requests/ci/api/
| RSpec | |
| app/assets/javascripts/
| spec/javascripts/
| Karma | Подробнее в разделе JavaScript. |
В идеальном мире контроллеры должны быть тонкими. Однако, когда это не так, можно написать системный/функциональный тест без JavaScript вместо теста контроллера. Причина заключается в том, что тестирование толстого контроллера обычно включает в себя много подмен, таких как:
controller.instance_variable_set(:@user, user)
и использование методов, которые устарели в Rails 5 (#23768).
Официальное определение: https://en.wikipedia.org/wiki/System_testing.
Эти виды тестов обеспечивают, что приложение работает так, как ожидают пользователи (т.е. black-box тестирование). Эти тесты должны проверять сценарий успеха для определенной страницы или набора страниц, и для каждого случая регрессии, который не был бы выявлен на более низких уровнях тестирования, должны быть добавлены тестовые случаи (т.е. если обнаружена регрессия, тесты регрессии должны быть добавлены на наименьшем возможном уровне).
Путь к тестам | Тестовый движок | Примечания |
---|---|---|
spec/features/ |
Capybara + RSpec | Если ваш тест имеет метаданные :js , то будет использоваться браузерный драйвер Poltergeist, в противном случае используется RackTest. |
features/ |
Spinach | Тесты Spinach устарели, вы не должны добавлять новые тесты Spinach. |
Model.count
увеличилось на один.Добавить тесты очень легко, но гораздо сложнее удалить или улучшить тесты, поэтому следует быть осторожным, чтобы не вводить слишком много (медленных и дублирующихся) спецификаций.
Причины, по которым следует следовать этим наилучшим практикам, следующие:
На самом деле, тестовые сценарии и шаги [входят в GitLab Rails], чтобы они всегда были синхронизированы с кодовой базой.[multiple pieces]: ./architecture.md#components [GitLab Shell]: https://gitlab.com/gitlab-org/gitlab-shell [GitLab Workhorse]: https://gitlab.com/gitlab-org/gitlab-workhorse [Gitaly]: https://gitlab.com/gitlab-org/gitaly [GitLab Pages]: https://gitlab.com/gitlab-org/gitlab-pages [GitLab Runner]: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner [GitLab Omnibus]: https://gitlab.com/gitlab-org/omnibus-gitlab [GitLab QA]: https://gitlab.com/gitlab-org/gitlab-qa [part of GitLab Rails]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/qa
Как и во многих вещах в жизни, решение о том, что следует тестировать на каждом уровне тестирования, является компромиссом:- Единичные тесты обычно дешевы, и вы должны рассматривать их как подвал вашего дома: вам нужны они, чтобы быть уверенным, что ваш код работает правильно. Однако если вы будете запускать только единичные тесты без интеграционных / системных тестов, вы можете пропустить большую картину!
Интеграционные тесты немного дороже, но не злоупотребляйте ими. Тестирование функции часто лучше, чем интеграционный тест, который имитирует много внутренних компонентов.
Системные тесты дороже (в сравнении с единичными тестами), особенно если они требуют JavaScript-драйвера. Убедитесь, что вы следуете рекомендациям в разделе Скорость.Другой способ посмотреть на это — подумать о "стоимости тестов". Это хорошо объяснено в этой статье, и основная идея заключается в том, что стоимость теста включает:
Время, затраченное на написание теста
Время, затраченное на выполнение теста каждый раз, когда запускается набор тестов
Время, затраченное на понимание теста
Время, затраченное на исправление теста, если он сломался, и подлежащий тестированию код в порядке
Возможно, время, затраченное на изменение кода, чтобы сделать его тестируемым.
Пожалуйста, обратитесь к специальному руководству по тестированию фронтенда.
describe ClassName
.described_class
вместо повторения имени описываемого класса
(это требование RuboCop)..method
для описания классовых методов и #method
для описания методов экземпляра.context
для тестирования ветвящегося логики.do...end
для before
и after
, даже если они бы поместились в одну строку.:each
для хуков, так как это значение по умолчанию.not_to
по сравнению с to_not
(это требование RuboCop).Gitlab.config.gitlab.host
вместо жесткого кодирования 'localhost'
.before
и after
предпочтительно использовать область :context
вместо :all
.[four-phase-test]: https://robots.thoughtbot.com/four-phase-test### Переменные let
Подмножество тестов GitLab's RSpec использует переменные let
для уменьшения
повторений. Однако, это иногда приходит за счет ясности, поэтому нам
нужно установить некоторые руководящие принципы для их использования в будущем:
let
предпочтительнее, чем экземплярные переменные. Локальные
переменные предпочтительнее, чем переменные let
.let
для уменьшения повторений на протяжении всего файла тестов.let
для определения переменных, используемых только одним
тестом; определяйте их как локальные переменные внутри блока it
теста.let
внутри верхнего уровня блока describe
, если
она используется только в более глубоко вложенных блоках context
или describe
.
Сохраняйте определение как можно ближе к месту использования.let
другой.let
, которая используется только в определении
другой. Используйте вспомогательный метод вместо этого.set
В некоторых случаях нет необходимости воссоздавать тот же объект для каждого
примера теста. Например, проект нужен для тестирования задач на том же проекте,
один проект будет достаточно для всего файла. Это можно достичь с помощью
использования set
аналогично использованию let
.rspec-set
работает только с объектами ActiveRecord, и перед новыми примерами тестов он перезагружает или воссоздает модель, только если это необходимо. То есть, когда вы изменили свойства или уничтожили объект.
Есть одна особенность; вы не можете ссылаться на модель, определенную в блоке let
, в блоке set
.
Timecop доступен в наших Ruby-тестах для проверки вещей, которые зависят от времени. Любые тесты, которые используют или проверяют что-то, зависящее от времени, должны использовать Timecop для предотвращения временных сбоев тестов.
Пример:
it 'is overdue' do
issue = build(:issue, due_date: Date.tomorrow)
Timecop.freeze(3.days.from_now) do
expect(issue).to be_overdue
end
end
ROLE_ACTION_spec.rb
, например, user_changes_password_spec.rb
.feature
на файл спецификации.spec/support/matchers/
. Matcherы могут быть расположены в подпапках, если они применимы только к определенному типу тестов (например, функции, запросы и т.д.), но не должны быть размещены там, если они применимы к нескольким типам тестов.### Общие контекстыВсе общие контексты должны размещаться в директории spec/support/shared_contexts/
. Общие контексты могут быть расположены в подпапках, если они применимы только к определенному типу тестов (например, функции, запросы и т.д.), но не должны быть размещены там, если они применимы к нескольким типам тестов.
Каждый файл должен содержать только один контекст и иметь описательное имя, например
spec/support/shared_contexts/controllers/githubish_import_controller_shared_context.rb
.
Все общие примеры должны размещаться в директории spec/support/shared_examples/
. Общие примеры могут быть расположены в подпапках, если они применимы только к определенному типу тестов (например, функции, запросы и т.д.), но не должны быть размещены там, если они применимы к нескольким типам тестов.
Каждый файл должен содержать только один пример и иметь описательное имя, например
spec/support/shared_examples/controllers/githubish_import_controller_shared_example.rb
.
spec/support/helpers/
. Помощники могут быть расположены в подпапках, если они применимы только к определённому типу тестов (например, функции, запросы и т.д.), но не должны быть размещены там, если они применимы к нескольким типам тестов.Помощники должны следовать конвенциям именования и пространств имен в Rails. Например, файл spec/support/helpers/cycle_analytics_helpers.rb
должен определять:module Spec
module Support
module Helpers
module CycleAnalyticsHelpers
def create_commit_referencing_issue(issue, branch_name: random_git_name)
project.repository.add_branch(user, branch_name, 'master')
create_commit("Commit for ##{issue.iid}", issue.project, user, branch_name)
end
end
end
end
end
Помощники не должны изменять конфигурацию RSpec. Например, модуль помощников, описанный выше, не должен включать:
RSpec.configure do |config|
config.include Spec::Support::Helpers::CycleAnalyticsHelpers
end
GitLab использует [factory_girl] в качестве замены тестовым_fixture.
spec/factories/
, названия файлов используют множественное число соответствующих моделей (фабрики User
определены в users.rb
).create(...)
вместо FactoryGirl.create(...)
.ActiveRecord
.
Пример.[factory_girl]: https://github.com/thoughtbot/factory_girl
[traits]: http://www.rubydoc.info/gems/factory_girl/file/GETTING_STARTED.md#Traits
Все фикстуры должны размещаться в spec/fixtures/
.
Файлы конфигурации RSpec — это файлы, которые изменяют конфигурацию RSpec (например, блоки RSpec.configure do |config|
). Они должны размещаться в spec/support/config/
.
Каждый файл должен быть связан с определенной областью, например spec/support/config/capybara.rb
, spec/support/config/carrierwave.rb
и т.д.
Помощники могут быть включены в файл spec/support/config/rspec.rb
. Если модуль помощников применим только к определенному типу тестов, он должен добавлять модификаторы к вызову config.include
. Например, если spec/support/helpers/cycle_analytics_helpers.rb
применим только к тестам :lib
и type: :model
, вы напишете следующее:
RSpec.configure do |config|
config.include Spec::Support::Helpers::CycleAnalyticsHelpers, :lib
config.include Spec::Support::Helpers::CycleAnalyticsHelpers, type: :model
end
Чтобы облегчить тестирование задач Rake, есть помощник, который можно включить вместо стандартного помощника Spec. Вместо require 'spec_helper'
используйте require 'rake_helper'
. Помощник включает spec_helper
для вас и настраивает несколько других вещей для упрощения тестирования задач Rake. Помощник Rake, по меньшей мере, перенаправляет stdout
, включает вспомогательные задачи выполнения и включает модуль поддержки RakeHelpers
для тестирования.Модуль RakeHelpers
предоставляет метод run_rake_task(<task>)
, чтобы сделать выполнение задач простым. См. spec/support/rake_helpers.rb
для всех доступных методов.
Пример:
require 'rake_helper'
describe 'gitlab:shell rake tasks' do
before do
Rake.application.rake_require 'tasks/gitlab/shell'
stub_warn_user_is_not_gitlab
end
describe 'установочная задача' do
it 'вызывает задачу create_hooks' do
expect(Rake::Task['gitlab:shell:create_hooks']).to receive(:invoke)
run_rake_task('gitlab:shell:install')
end
end
end
GitLab имеет огромный набор тестов, который, без [параллелизации], может занять часы на выполнение. Важно, чтобы мы стремились писать тесты, которые точны и эффективны а также быстры.
Вот несколько вещей, которые стоит учитывать в отношении производительности тестирования:
double
и spy
быстрее, чем FactoryGirl.build(...)
FactoryGirl.build(...)
и .build_stubbed
быстрее, чем .create
.build
, build_stubbed
, attributes_for
, spy
или double
будут достаточно.create(:empty_project)
вместо create(:project)
, когда вам не нужен подлежащий Git репозиторий. Операции с файловой системой медленны!@javascript
в Spinach или :js
в RSpec), если это на самом деле необходимо для теста быть корректным. Тестирование безголовых браузеров медленно!knapsack
на этапе подготовки должна обеспечивать наличие файла knapsack/${CI_PROJECT_NAME}/rspec_report-master.json
:
knapsack/${CI_PROJECT_NAME}/rspec_report-master.json
загружается из S3. Если он отсутствует, файл инициализируется значением {}
.rspec x y
выполняется с помощью knapsack rspec
и должна иметь равномерно распределённую долю тестов:
knapsack/${CI_PROJECT_NAME}/rspec_report-master.json
, так как "артефакты всех предыдущих этапов передаются по умолчанию". ^1
KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
.knapsack
выполняет свою работу правильно, файлы тестов, которые выполняются, должны быть перечислены в разделе Report specs
, а не в разделе Leftover specs
.update-knapsack
собирает все файлы knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
из задач rspec x y
и объединяет их в один файл knapsack/${CI_PROJECT_NAME}/rspec_report-master.json
, который затем загружается в S3. После этого следующий пайплайн будет использовать актуальный файл knapsack/${CI_PROJECT_NAME}/rspec_report-master.json
. Та же стратегия применяется для тестов Spinach.Набор тестов GitLab мониторится для ветки master
и для любой ветки, которая включает rspec-profile
в своё имя.Доступен публичный дашборд для всех желающих. Вы можете посмотреть на самые медленные файлы тестов и попытаться их улучшить.
master
и для любой ветки, которая включает mysql
в своё имя.GitLab перешёл с Cucumber на Spinach для своих функциональных/интеграционных тестов в сентябре 2012 года.
С марта 2016 года мы [стремимся избегать добавления новых тестов Spinach] (https://gitlab.com/gitlab-org/gitlab-ce/issues/14121) в будущем, предпочитая RSpec функциональные тесты.
Добавление новых сценариев Spinach допустимо только если новый сценарий требует не более одного нового определения шага. Если требуется больше, тест следует переimplement using RSpec instead.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )