1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/panda26-gitlab

Клонировать/Скачать
testing.md 35 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 26.05.2025 02:09 64486eb

Правила и руководства по тестированию

Это руководство описывает стандарты и лучшие практики для автоматизированного тестирования 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).

О KarmaКак вы могли заметить, Karma присутствует как в категории Unit tests, так и в категории Integration tests. Это потому что Karma — это инструмент, который предоставляет среду для выполнения JavaScript тестов, поэтому вы можете либо выполнять unit тесты (например, тестирование одного метода JavaScript), либо integration тесты (например, тестирование компонента, состоящего из нескольких компонентов).### Системные тесты или функциональные тесты

Официальное определение: https://en.wikipedia.org/wiki/System_testing.

Эти виды тестов обеспечивают, что приложение работает так, как ожидают пользователи (т.е. black-box тестирование). Эти тесты должны проверять сценарий успеха для определенной страницы или набора страниц, и для каждого случая регрессии, который не был бы выявлен на более низких уровнях тестирования, должны быть добавлены тестовые случаи (т.е. если обнаружена регрессия, тесты регрессии должны быть добавлены на наименьшем возможном уровне).

Путь к тестам Тестовый движок Примечания
spec/features/ Capybara + RSpec Если ваш тест имеет метаданные :js, то будет использоваться браузерный драйвер Poltergeist, в противном случае используется RackTest.
features/ Spinach Тесты Spinach устарели, вы не должны добавлять новые тесты Spinach.

Наилучшие практики- Создавайте только необходимые записи в базе данных

  • Тестируйте счастливый путь и менее счастливый путь, но этого достаточно
  • Каждый другой возможный путь следует тестировать с помощью Unit или Integration тестов
  • Тестируйте то, что отображается на странице, а не внутренности моделей ActiveRecord. Например, если вы хотите проверить, что запись была создана, добавьте ожидания, что её атрибуты отображаются на странице, а не то, что Model.count увеличилось на один.
  • Можно искать элементы DOM, но не злоупотребляйте этим, так как это делает тесты более хрупкимиЕсли мы уверены, что низкоуровневые компоненты работают хорошо (и мы должны быть уверены, если у нас достаточно Unit & Integration тестов), мы не должны нуждаться в дублировании их тщательного тестирования на уровне System тестов.

Добавить тесты очень легко, но гораздо сложнее удалить или улучшить тесты, поэтому следует быть осторожным, чтобы не вводить слишком много (медленных и дублирующихся) спецификаций.

Причины, по которым следует следовать этим наилучшим практикам, следующие:

  • System тесты медленны для выполнения, так как они запускают всю стек приложения в безголовом браузере, и ещё медленнее, когда они интегрируют JS-драйвер.
  • Когда system тесты выполняются с использованием JS-драйвера, тесты выполняются в отдельном потоке от приложения. Это означает, что они не делятся базовым соединением с базой данных, и вашему тесту придётся подтверждать транзакции, чтобы запущенное приложение могло видеть данные (и наоборот). В этом случае нам нужно очищать базу данных после каждого теста, а не просто откатывать транзакцию (более быстрая стратегия, используемая для других типов тестов). Это медленнее, чем транзакции, поэтому мы хотим использовать очистку только по мере необходимости.

Чёрный ящик тесты или End-to-end тестыGitLab состоит из [нескольких компонентов], таких как [GitLab Shell], [GitLab Workhorse], [Gitaly], [GitLab Pages], [GitLab Runner] и GitLab Rails. Все эти компоненты настраиваются и упаковываются с помощью [GitLab Omnibus].[GitLab QA] — это инструмент, который позволяет проверить, что все эти части интегрируются правильно вместе, создавая Docker-образ для данной версии GitLab Rails и запуская функциональные тесты (то есть используя Capybara) против него.

На самом деле, тестовые сценарии и шаги [входят в 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-драйвера. Убедитесь, что вы следуете рекомендациям в разделе Скорость.Другой способ посмотреть на это — подумать о "стоимости тестов". Это хорошо объяснено в этой статье, и основная идея заключается в том, что стоимость теста включает:

  • Время, затраченное на написание теста

  • Время, затраченное на выполнение теста каждый раз, когда запускается набор тестов

  • Время, затраченное на понимание теста

  • Время, затраченное на исправление теста, если он сломался, и подлежащий тестированию код в порядке

  • Возможно, время, затраченное на изменение кода, чтобы сделать его тестируемым.

Тестирование фронтенда

Пожалуйста, обратитесь к специальному руководству по тестированию фронтенда.

RSpec### Общие рекомендации

  • Используйте единственный, верхнеуровневый блок describe ClassName.
  • Используйте described_class вместо повторения имени описываемого класса (это требование RuboCop).
  • Используйте .method для описания классовых методов и #method для описания методов экземпляра.
  • Используйте context для тестирования ветвящегося логики.
  • Используйте многострочные блоки do...end для before и after, даже если они бы поместились в одну строку.
  • Не описывайте символы (см. Опасности).
  • Не утверждайте абсолютное значение атрибута, сгенерированного последовательностью (см. Опасности).
  • Не предоставляйте аргумент :each для хуков, так как это значение по умолчанию.
  • Предпочитайте not_to по сравнению с to_not (это требование RuboCop).
  • Попытайтесь соответствовать порядку тестов порядку внутри класса.
  • Попытайтесь следовать [шаблону Four-Phase Test][four-phase-test], используя новую строку для разделения фаз.
  • Попытайтесь использовать 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 на файл спецификации.
  • Используйте заголовки сценариев, которые описывают пути успеха и неудачи.
  • Избегайте заголовков сценариев, которые не добавляют никакой информации, таких как "успешно".
  • Избегайте заголовков сценариев, которые повторяют заголовок функции.

MatcherыПользовательские matcherы должны создаваться для уточнения намерения и/или скрытия сложности ожиданий RSpec. Они должны размещаться в директории 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.

ПомощникиПомощники обычно являются модулями, предоставляющими некоторые методы для скрытия сложности конкретных примеров RSpec. Вы можете определить помощники в файлах RSpec, если они не предназначены для использования другими тестами. В противном случае они должны размещаться в директории 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).
  • В одном файле должно быть только одно определение фабрики на уровне верхнего каталога.
  • Методы FactoryGirl смешиваются со всеми группами RSpec. Это означает, что вы можете (и должны) вызывать create(...) вместо FactoryGirl.create(...).
  • Используйте [traits] для упрощения определений и использования.
  • При определении фабрики не определяйте атрибуты, которые не требуются для прохождения валидации результирующего объекта.
  • При создании объекта из фабрики не передавайте атрибуты, которые не требуются для теста.
  • Фабрики не должны ограничиваться объектами 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

Чтобы облегчить тестирование задач 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 (через @javascript в Spinach или :js в RSpec), если это на самом деле необходимо для теста быть корректным. Тестирование безголовых браузеров медленно!

Параллелизация набора тестов на CIНаша текущая конфигурация параллелизации CI выглядит следующим образом:

  1. Задача knapsack на этапе подготовки должна обеспечивать наличие файла knapsack/${CI_PROJECT_NAME}/rspec_report-master.json:
    • Файл knapsack/${CI_PROJECT_NAME}/rspec_report-master.json загружается из S3. Если он отсутствует, файл инициализируется значением {}.
  2. Каждая задача 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.
  3. Задача 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 в своё имя.Доступен публичный дашборд для всех желающих. Вы можете посмотреть на самые медленные файлы тестов и попытаться их улучшить.

Настройка CI

  • В CE набор тестов по умолчанию запускается только против PostgreSQL. Мы дополнительно запускаем его против MySQL для тегов, master и для любой ветки, которая включает mysql в своё имя.
  • В EE набор тестов всегда запускается как против PostgreSQL, так и против MySQL.

Spinach (функциональные) тесты

GitLab перешёл с Cucumber на Spinach для своих функциональных/интеграционных тестов в сентябре 2012 года.

С марта 2016 года мы [стремимся избегать добавления новых тестов Spinach] (https://gitlab.com/gitlab-org/gitlab-ce/issues/14121) в будущем, предпочитая RSpec функциональные тесты.

Добавление новых сценариев Spinach допустимо только если новый сценарий требует не более одного нового определения шага. Если требуется больше, тест следует переimplement using RSpec instead.


Вернуться к документации по разработке

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/panda26-gitlab.git
git@api.gitlife.ru:oschina-mirror/panda26-gitlab.git
oschina-mirror
panda26-gitlab
panda26-gitlab
master